mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-06-03 15:10:19 +00:00
加锁文章目录丢失
This commit is contained in:
@@ -18,6 +18,7 @@ import { useEffect, useState } from 'react'
|
|||||||
*/
|
*/
|
||||||
const Slug = props => {
|
const Slug = props => {
|
||||||
const { post } = props
|
const { post } = props
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
// 文章锁🔐
|
// 文章锁🔐
|
||||||
const [lock, setLock] = useState(post?.password && post?.password !== '')
|
const [lock, setLock] = useState(post?.password && post?.password !== '')
|
||||||
@@ -27,9 +28,14 @@ const Slug = props => {
|
|||||||
* @param {*} result
|
* @param {*} result
|
||||||
*/
|
*/
|
||||||
const validPassword = passInput => {
|
const validPassword = passInput => {
|
||||||
const encrypt = md5(post.slug + passInput)
|
if (!post) {
|
||||||
if (passInput && encrypt === post.password) {
|
return false
|
||||||
|
}
|
||||||
|
const encrypt = md5(post?.slug + passInput)
|
||||||
|
if (passInput && encrypt === post?.password) {
|
||||||
setLock(false)
|
setLock(false)
|
||||||
|
// 输入密码存入localStorage,下次自动提交
|
||||||
|
localStorage.setItem('password_' + router.asPath, passInput)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -49,8 +55,28 @@ const Slug = props => {
|
|||||||
post.toc = getPageTableOfContents(post, post.blockMap)
|
post.toc = getPageTableOfContents(post, post.blockMap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 从localStorage中读取上次记录 自动提交密码
|
||||||
|
const passInput = localStorage.getItem('password_' + router.asPath)
|
||||||
|
if (passInput) {
|
||||||
|
validPassword(passInput)
|
||||||
|
}
|
||||||
}, [post])
|
}, [post])
|
||||||
|
|
||||||
|
// 文章加载
|
||||||
|
useEffect(() => {
|
||||||
|
if (lock) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 文章解锁后生成目录与内容
|
||||||
|
if (post?.blockMap?.block) {
|
||||||
|
post.content = Object.keys(post.blockMap.block).filter(
|
||||||
|
key => post.blockMap.block[key]?.value?.parent_id === post.id
|
||||||
|
)
|
||||||
|
post.toc = getPageTableOfContents(post, post.blockMap)
|
||||||
|
}
|
||||||
|
}, [post, lock])
|
||||||
|
|
||||||
props = { ...props, lock, setLock, validPassword }
|
props = { ...props, lock, setLock, validPassword }
|
||||||
// 根据页面路径加载不同Layout文件
|
// 根据页面路径加载不同Layout文件
|
||||||
const Layout = getLayoutByTheme({
|
const Layout = getLayoutByTheme({
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ export const ArticleLock = props => {
|
|||||||
*/
|
*/
|
||||||
const submitPassword = () => {
|
const submitPassword = () => {
|
||||||
const p = document.getElementById('password')
|
const p = document.getElementById('password')
|
||||||
|
|
||||||
// 验证失败提示
|
// 验证失败提示
|
||||||
if (!validPassword(p?.value)) {
|
if (!validPassword(p?.value)) {
|
||||||
const tips = document.getElementById('tips')
|
const tips = document.getElementById('tips')
|
||||||
@@ -28,23 +27,12 @@ export const ArticleLock = props => {
|
|||||||
tips.innerHTML = ''
|
tips.innerHTML = ''
|
||||||
tips.innerHTML = `<div class='text-red-500 animate__shakeX animate__animated'>${locale.COMMON.PASSWORD_ERROR}</div>`
|
tips.innerHTML = `<div class='text-red-500 animate__shakeX animate__animated'>${locale.COMMON.PASSWORD_ERROR}</div>`
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// 输入密码存入localStorage,下次自动提交
|
|
||||||
localStorage.setItem('password_' + router.asPath, p?.value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 选中密码输入框并将其聚焦
|
// 选中密码输入框并将其聚焦
|
||||||
passwordInputRef.current.focus()
|
passwordInputRef.current.focus()
|
||||||
|
|
||||||
// 从localStorage中读取上次记录 自动提交密码
|
|
||||||
const p = localStorage.getItem('password_' + router.asPath)
|
|
||||||
console.log('pp', p, document.getElementById('password'))
|
|
||||||
if (p) {
|
|
||||||
document.getElementById('password').value = p
|
|
||||||
submitPassword()
|
|
||||||
}
|
|
||||||
}, [router])
|
}, [router])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react'
|
import { isBrowser } from '@/lib/utils'
|
||||||
import throttle from 'lodash.throttle'
|
import throttle from 'lodash.throttle'
|
||||||
import { uuidToId } from 'notion-utils'
|
import { uuidToId } from 'notion-utils'
|
||||||
import { isBrowser } from '@/lib/utils'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 目录导航组件
|
* 目录导航组件
|
||||||
@@ -24,66 +24,78 @@ const Catalog = ({ post }) => {
|
|||||||
}, [post])
|
}, [post])
|
||||||
|
|
||||||
const throttleMs = 200
|
const throttleMs = 200
|
||||||
const actionSectionScrollSpy = useCallback(throttle(() => {
|
const actionSectionScrollSpy = useCallback(
|
||||||
const sections = document.getElementsByClassName('notion-h')
|
throttle(() => {
|
||||||
let prevBBox = null
|
const sections = document.getElementsByClassName('notion-h')
|
||||||
let currentSectionId = null
|
let prevBBox = null
|
||||||
for (let i = 0; i < sections.length; ++i) {
|
let currentSectionId = null
|
||||||
const section = sections[i]
|
for (let i = 0; i < sections.length; ++i) {
|
||||||
if (!section || !(section instanceof Element)) continue
|
const section = sections[i]
|
||||||
if (!currentSectionId) {
|
if (!section || !(section instanceof Element)) continue
|
||||||
currentSectionId = section.getAttribute('data-id')
|
if (!currentSectionId) {
|
||||||
|
currentSectionId = section.getAttribute('data-id')
|
||||||
|
}
|
||||||
|
const bbox = section.getBoundingClientRect()
|
||||||
|
const prevHeight = prevBBox ? bbox.top - prevBBox.bottom : 0
|
||||||
|
const offset = Math.max(150, prevHeight / 4)
|
||||||
|
// GetBoundingClientRect returns values relative to viewport
|
||||||
|
if (bbox.top - offset < 0) {
|
||||||
|
currentSectionId = section.getAttribute('data-id')
|
||||||
|
prevBBox = bbox
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// No need to continue loop, if last element has been detected
|
||||||
|
break
|
||||||
}
|
}
|
||||||
const bbox = section.getBoundingClientRect()
|
setActiveSection(currentSectionId)
|
||||||
const prevHeight = prevBBox ? bbox.top - prevBBox.bottom : 0
|
const tocIds = post?.toc?.map(t => uuidToId(t.id)) || []
|
||||||
const offset = Math.max(150, prevHeight / 4)
|
const index = tocIds.indexOf(currentSectionId) || 0
|
||||||
// GetBoundingClientRect returns values relative to viewport
|
if (isBrowser && tocIds?.length > 0) {
|
||||||
if (bbox.top - offset < 0) {
|
for (const tocWrapper of document?.getElementsByClassName(
|
||||||
currentSectionId = section.getAttribute('data-id')
|
'toc-wrapper'
|
||||||
prevBBox = bbox
|
)) {
|
||||||
continue
|
tocWrapper?.scrollTo({ top: 28 * index, behavior: 'smooth' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// No need to continue loop, if last element has been detected
|
}, throttleMs)
|
||||||
break
|
)
|
||||||
}
|
|
||||||
setActiveSection(currentSectionId)
|
|
||||||
const tocIds = post?.toc?.map((t) => uuidToId(t.id)) || []
|
|
||||||
const index = tocIds.indexOf(currentSectionId) || 0
|
|
||||||
if (isBrowser && tocIds?.length > 0) {
|
|
||||||
for (const tocWrapper of document?.getElementsByClassName('toc-wrapper')) {
|
|
||||||
tocWrapper?.scrollTo({ top: 28 * index, behavior: 'smooth' })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, throttleMs))
|
|
||||||
|
|
||||||
// 无目录就直接返回空
|
// 无目录就直接返回空
|
||||||
if (!toc || toc.length < 1) {
|
if (!toc || toc?.length < 1) {
|
||||||
return null
|
return <></>
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
console.log('渲染toc', toc)
|
||||||
<div id='toc-wrapper' className='toc-wrapper overflow-y-auto my-2 max-h-80 overscroll-none scroll-hidden'>
|
|
||||||
<nav className='h-full text-black'>
|
return (
|
||||||
{toc.map((tocItem) => {
|
<>
|
||||||
const id = uuidToId(tocItem.id)
|
<div
|
||||||
return (
|
id='toc-wrapper'
|
||||||
<a
|
className='toc-wrapper overflow-y-auto my-2 max-h-80 overscroll-none scroll-hidden'>
|
||||||
key={id}
|
<nav className='h-full text-black'>
|
||||||
href={`#${id}`}
|
{toc?.map(tocItem => {
|
||||||
className={`notion-table-of-contents-item duration-300 transform font-light dark:text-gray-300
|
const id = uuidToId(tocItem.id)
|
||||||
notion-table-of-contents-item-indent-level-${tocItem.indentLevel} `}
|
return (
|
||||||
>
|
<a
|
||||||
<span style={{ display: 'inline-block', marginLeft: tocItem.indentLevel * 16 }}
|
key={id}
|
||||||
className={`truncate ${activeSection === id ? 'font-bold text-gray-500 underline' : ''}`}
|
href={`#${id}`}
|
||||||
>
|
className={`notion-table-of-contents-item duration-300 transform font-light dark:text-gray-300
|
||||||
{tocItem.text}
|
notion-table-of-contents-item-indent-level-${tocItem.indentLevel} `}>
|
||||||
</span>
|
<span
|
||||||
</a>
|
style={{
|
||||||
)
|
display: 'inline-block',
|
||||||
})}
|
marginLeft: tocItem.indentLevel * 16
|
||||||
</nav>
|
}}
|
||||||
</div>
|
className={`truncate ${activeSection === id ? 'font-bold text-gray-500 underline' : ''}`}>
|
||||||
</>
|
{tocItem.text}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Catalog
|
export default Catalog
|
||||||
|
|||||||
Reference in New Issue
Block a user