加锁文章目录丢失

This commit is contained in:
tangly1024.com
2024-05-13 14:43:18 +08:00
parent 741528e9f2
commit 3aa1e6f0be
3 changed files with 96 additions and 70 deletions

View File

@@ -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({

View File

@@ -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 (

View File

@@ -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