diff --git a/lib/lang/en-US.js b/lib/lang/en-US.js
index 5e02c979..00414875 100644
--- a/lib/lang/en-US.js
+++ b/lib/lang/en-US.js
@@ -29,7 +29,10 @@ export default {
VIEWS: 'Views',
COPYRIGHT_NOTICE: 'All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!',
RESULT_OF_SEARCH: 'Results Found',
- ARTICLE_DETAIL: 'Article Details'
+ ARTICLE_DETAIL: 'Article Details',
+ PASSWORD_ERROR: 'Password Error!',
+ ARTICLE_LOCK_TIPS: 'Please Enter the password:',
+ SUBMIT: 'Submit'
},
PAGINATION: {
PREV: 'Prev',
diff --git a/lib/lang/zh-CN.js b/lib/lang/zh-CN.js
index 915c1a9a..4417a270 100644
--- a/lib/lang/zh-CN.js
+++ b/lib/lang/zh-CN.js
@@ -31,7 +31,10 @@ export default {
VIEWS: '次查看',
COPYRIGHT_NOTICE: '本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。',
RESULT_OF_SEARCH: '篇搜索到的结果',
- ARTICLE_DETAIL: '文章详情'
+ ARTICLE_DETAIL: '文章详情',
+ PASSWORD_ERROR: '密码错误!',
+ ARTICLE_LOCK_TIPS: '文章已上锁,请输入访问密码',
+ SUBMIT: '提交'
},
PAGINATION: {
PREV: '上一页',
diff --git a/lib/lang/zh-TW.js b/lib/lang/zh-TW.js
index 087c7713..a7f648f4 100644
--- a/lib/lang/zh-TW.js
+++ b/lib/lang/zh-TW.js
@@ -31,7 +31,10 @@ export default {
VIEWS: '次查看',
COPYRIGHT_NOTICE: '本文採用 CC BY-NC-SA 4.0 許可協議,轉載請註明出處。',
RESULT_OF_SEARCH: '篇搜尋到的结果',
- ARTICLE_DETAIL: '完整文章'
+ ARTICLE_DETAIL: '完整文章',
+ PASSWORD_ERROR: '密碼錯誤!',
+ ARTICLE_LOCK_TIPS: '文章已上鎖,請輸入訪問密碼',
+ SUBMIT: '提交'
},
PAGINATION: {
PREV: '上一頁',
diff --git a/themes/empty/LayoutSlug.js b/themes/empty/LayoutSlug.js
index caa2bbb2..d2808e51 100644
--- a/themes/empty/LayoutSlug.js
+++ b/themes/empty/LayoutSlug.js
@@ -14,6 +14,9 @@ import {
NotionRenderer
} from 'react-notion-x'
import LayoutBase from './LayoutBase'
+import { useState, useRef, useEffect } from 'react'
+import { ArticleLock } from './components/ArticleLock'
+import mediumZoom from 'medium-zoom'
const mapPageUrl = id => {
return 'https://www.notion.so/' + id.replace(/-/g, '')
@@ -27,18 +30,46 @@ export const LayoutSlug = props => {
type: 'article',
tags: post.tags
}
+ // 文章加锁
+ const articleLock = post.password && post.password !== ''
+ const [lock, setLock] = useState(articleLock)
+ const validPassword = result => {
+ if (result) {
+ setLock(false)
+ }
+ }
- if (post?.blockMap?.block) {
+ if (!lock && post?.blockMap?.block) {
post.content = Object.keys(post.blockMap.block)
post.toc = getPageTableOfContents(post, post.blockMap)
}
+ const zoom =
+ typeof window !== 'undefined' &&
+ mediumZoom({
+ container: '.notion-viewport',
+ background: 'rgba(0, 0, 0, 0.2)',
+ margin: getMediumZoomMargin()
+ })
+ const zoomRef = useRef(zoom ? zoom.clone() : null)
+ useEffect(() => {
+ // 将所有container下的所有图片添加medium-zoom
+ const container = document.getElementById('notion-article')
+ const imgList = container?.getElementsByTagName('img')
+ if (imgList && zoomRef.current) {
+ for (let i = 0; i < imgList.length; i++) {
+ zoomRef.current.attach(imgList[i])
+ }
+ }
+ })
return (
{post?.title}
-
-
+
+ {lock && }
+
+ {!lock &&
{post.blockMap && (
{
}}
/>
)}
-
-
+ }
+
)
}
+
+function getMediumZoomMargin () {
+ const width = window.innerWidth
+
+ if (width < 500) {
+ return 8
+ } else if (width < 800) {
+ return 20
+ } else if (width < 1280) {
+ return 30
+ } else if (width < 1600) {
+ return 40
+ } else if (width < 1920) {
+ return 48
+ } else {
+ return 72
+ }
+}
diff --git a/themes/empty/components/ArticleLock.js b/themes/empty/components/ArticleLock.js
new file mode 100644
index 00000000..bfdd00ce
--- /dev/null
+++ b/themes/empty/components/ArticleLock.js
@@ -0,0 +1,40 @@
+import { useGlobal } from '@/lib/global'
+
+/**
+ * 加密文章校验组件
+ * @param {password, validPassword} props
+ * @param password 正确的密码
+ * @param validPassword(bool) 回调函数,校验正确回调入参为true
+ * @returns
+ */
+export const ArticleLock = props => {
+ const { password, validPassword } = props
+ const { locale } = useGlobal()
+
+ const submitPassword = () => {
+ const p = document.getElementById('password')
+ if (p && p.value && p.value === password) {
+ validPassword(true)
+ } else {
+ const tips = document.getElementById('tips')
+ if (tips) {
+ tips.innerHTML = ''
+ tips.innerHTML = `
${locale.COMMON.PASSWORD_ERROR}
`
+ }
+ }
+ }
+
+ return
+
+
{locale.COMMON.ARTICLE_LOCK_TIPS}
+
+
+
+ {locale.COMMON.SUBMIT}
+
+
+
+
+
+
+}
diff --git a/themes/fukasawa/LayoutSlug.js b/themes/fukasawa/LayoutSlug.js
index 6834da3e..90e53ecf 100644
--- a/themes/fukasawa/LayoutSlug.js
+++ b/themes/fukasawa/LayoutSlug.js
@@ -8,6 +8,8 @@ import 'prismjs/components/prism-python'
import 'prismjs/components/prism-typescript'
import ArticleDetail from './components/ArticleDetail'
import LayoutBase from './LayoutBase'
+import { useState } from 'react'
+import { ArticleLock } from './components/ArticleLock'
export const LayoutSlug = (props) => {
const { post } = props
@@ -18,6 +20,15 @@ export const LayoutSlug = (props) => {
tags: post.tags
}
+ // 文章加锁
+ const articleLock = post.password && post.password !== ''
+ const [lock, setLock] = useState(articleLock)
+ const validPassword = result => {
+ if (result) {
+ setLock(false)
+ }
+ }
+
if (post?.blockMap?.block) {
post.content = Object.keys(post.blockMap.block)
post.toc = getPageTableOfContents(post, post.blockMap)
@@ -25,7 +36,8 @@ export const LayoutSlug = (props) => {
return (
-
-
+ {!lock && }
+ {lock && }
+
)
}
diff --git a/themes/fukasawa/components/ArticleLock.js b/themes/fukasawa/components/ArticleLock.js
new file mode 100644
index 00000000..0d10b513
--- /dev/null
+++ b/themes/fukasawa/components/ArticleLock.js
@@ -0,0 +1,49 @@
+import { useGlobal } from '@/lib/global'
+
+/**
+ * 加密文章校验组件
+ * @param {password, validPassword} props
+ * @param password 正确的密码
+ * @param validPassword(bool) 回调函数,校验正确回调入参为true
+ * @returns
+ */
+export const ArticleLock = props => {
+ const { password, validPassword } = props
+ const { locale } = useGlobal()
+
+ const submitPassword = () => {
+ const p = document.getElementById('password')
+ if (p && p.value && p.value === password) {
+ validPassword(true)
+ } else {
+ const tips = document.getElementById('tips')
+ if (tips) {
+ tips.innerHTML = ''
+ tips.innerHTML = `${locale.COMMON.PASSWORD_ERROR}
`
+ }
+ }
+ }
+
+ return (
+
+
+
+
{locale.COMMON.ARTICLE_LOCK_TIPS}
+
+
+
+ {locale.COMMON.SUBMIT}
+
+
+
+
+
+
+
)
+}
diff --git a/themes/hexo/LayoutSlug.js b/themes/hexo/LayoutSlug.js
index 5e152c72..8628e521 100644
--- a/themes/hexo/LayoutSlug.js
+++ b/themes/hexo/LayoutSlug.js
@@ -7,8 +7,9 @@ import 'prismjs/components/prism-javascript'
import 'prismjs/components/prism-markup'
import 'prismjs/components/prism-python'
import 'prismjs/components/prism-typescript'
-import { useRef } from 'react'
+import { useRef, useState } from 'react'
import ArticleDetail from './components/ArticleDetail'
+import { ArticleLock } from './components/ArticleLock'
import HeaderArticle from './components/HeaderArticle'
import JumpToCommentButton from './components/JumpToCommentButton'
import TocDrawer from './components/TocDrawer'
@@ -24,7 +25,16 @@ export const LayoutSlug = props => {
tags: post.tags
}
- if (post?.blockMap?.block) {
+ // 文章加锁
+ const articleLock = post.password && post.password !== ''
+ const [lock, setLock] = useState(articleLock)
+ const validPassword = result => {
+ if (result) {
+ setLock(false)
+ }
+ }
+
+ if (!lock && post?.blockMap?.block) {
post.content = Object.keys(post.blockMap.block)
post.toc = getPageTableOfContents(post, post.blockMap)
}
@@ -53,7 +63,8 @@ export const LayoutSlug = props => {
floatSlot={floatSlot}
>
-
+ {!lock &&
}
+ {lock &&
}
diff --git a/themes/hexo/components/ArticleLock.js b/themes/hexo/components/ArticleLock.js
new file mode 100644
index 00000000..71d2354f
--- /dev/null
+++ b/themes/hexo/components/ArticleLock.js
@@ -0,0 +1,39 @@
+import { useGlobal } from '@/lib/global'
+
+/**
+ * 加密文章校验组件
+ * @param {password, validPassword} props
+ * @param password 正确的密码
+ * @param validPassword(bool) 回调函数,校验正确回调入参为true
+ * @returns
+ */
+export const ArticleLock = props => {
+ const { password, validPassword } = props
+ const { locale } = useGlobal()
+ const submitPassword = () => {
+ const p = document.getElementById('password')
+ if (p && p.value && p.value === password) {
+ validPassword(true)
+ } else {
+ const tips = document.getElementById('tips')
+ if (tips) {
+ tips.innerHTML = ''
+ tips.innerHTML = `
${locale.COMMON.PASSWORD_ERROR}
`
+ }
+ }
+ }
+
+ return
+
+
{locale.COMMON.ARTICLE_LOCK_TIPS}
+
+
+
+ {locale.COMMON.SUBMIT}
+
+
+
+
+
+
+}
diff --git a/themes/medium/LayoutSlug.js b/themes/medium/LayoutSlug.js
index ad12f872..ef54d6c7 100644
--- a/themes/medium/LayoutSlug.js
+++ b/themes/medium/LayoutSlug.js
@@ -1,38 +1,16 @@
import BLOG from '@/blog.config'
import { getPageTableOfContents } from 'notion-utils'
-import 'prismjs'
-import 'prismjs/components/prism-bash'
-import 'prismjs/components/prism-javascript'
-import 'prismjs/components/prism-markup'
-import 'prismjs/components/prism-python'
-import 'prismjs/components/prism-typescript'
-import {
- Code,
- Collection,
- CollectionRow,
- Equation,
- NotionRenderer
-} from 'react-notion-x'
-import LayoutBase from './LayoutBase'
-import Comment from '@/components/Comment'
-import Image from 'next/image'
-import { useGlobal } from '@/lib/global'
-import formatDate from '@/lib/formatDate'
-import Link from 'next/link'
-import mediumZoom from 'medium-zoom'
-import React, { useEffect, useRef } from 'react'
-import ArticleAround from './components/ArticleAround'
-import Catalog from './components/Catalog'
-import CategoryItem from './components/CategoryItem'
-import TagItemMini from './components/TagItemMini'
-import CONFIG_MEDIUM from './config_medium'
-const mapPageUrl = id => {
- return 'https://www.notion.so/' + id.replace(/-/g, '')
-}
+import LayoutBase from './LayoutBase'
+import { useGlobal } from '@/lib/global'
+import mediumZoom from 'medium-zoom'
+import React, { useEffect, useRef, useState } from 'react'
+import Catalog from './components/Catalog'
+import { ArticleDetail } from './components/ArticleDetail'
+import { ArticleLock } from './components/ArticleLock'
export const LayoutSlug = props => {
- const { post, prev, next } = props
+ const { post } = props
const meta = {
title: `${post.title} | ${BLOG.TITLE}`,
description: post.summary,
@@ -40,15 +18,20 @@ export const LayoutSlug = props => {
tags: post.tags
}
- if (post?.blockMap?.block) {
+ // 文章加锁
+ const articleLock = post.password && post.password !== ''
+ const [lock, setLock] = useState(articleLock)
+ const validPassword = result => {
+ if (result) {
+ setLock(false)
+ }
+ }
+
+ if (!lock && post?.blockMap?.block) {
post.content = Object.keys(post.blockMap.block)
post.toc = getPageTableOfContents(post, post.blockMap)
}
const { locale } = useGlobal()
- const date = formatDate(
- post?.date?.start_date || post.createdTime,
- locale.LOCALE
- )
const zoom =
typeof window !== 'undefined' &&
@@ -83,68 +66,10 @@ export const LayoutSlug = props => {
showInfoCard={true}
slotRight={slotRight}
>
-
{post?.title}
-
-
- <>
-
-
- {BLOG.AUTHOR}
-
- >
-
- {date}
-
-
-
-
-
-
- {/* Notion文章主体 */}
-
- {post.blockMap && (
-
- )}
-
-
-
-
- { CONFIG_MEDIUM.POST_DETAIL_CATEGORY && post.category &&
}
-
- { CONFIG_MEDIUM.POST_DETAIL_TAG && post?.tagItems?.map(tag => )}
-
-
-
-
-
+ {!lock &&
}
+
+ {lock &&
}
)
}
diff --git a/themes/medium/components/ArticleDetail.js b/themes/medium/components/ArticleDetail.js
new file mode 100644
index 00000000..6c454198
--- /dev/null
+++ b/themes/medium/components/ArticleDetail.js
@@ -0,0 +1,102 @@
+import {
+ Code,
+ Collection,
+ CollectionRow,
+ Equation,
+ NotionRenderer
+} from 'react-notion-x'
+import Comment from '@/components/Comment'
+import Image from 'next/image'
+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 'prismjs'
+import 'prismjs/components/prism-bash'
+import 'prismjs/components/prism-javascript'
+import 'prismjs/components/prism-markup'
+import 'prismjs/components/prism-python'
+import 'prismjs/components/prism-typescript'
+import BLOG from '@/blog.config'
+
+const mapPageUrl = id => {
+ return 'https://www.notion.so/' + id.replace(/-/g, '')
+}
+
+export const ArticleDetail = props => {
+ const { post, prev, next } = props
+ const { locale } = useGlobal()
+
+ const date = formatDate(
+ post?.date?.start_date || post.createdTime,
+ locale.LOCALE
+ )
+ return <>
+
{post?.title}
+
+
+ <>
+
+
+ {BLOG.AUTHOR}
+
+ >
+
+ {date}
+
+
+
+
+
+
+ {/* Notion文章主体 */}
+
+ {post.blockMap && (
+
+ )}
+
+
+
+
+
+ { CONFIG_MEDIUM.POST_DETAIL_CATEGORY && post.category &&
}
+
+ { CONFIG_MEDIUM.POST_DETAIL_TAG && post?.tagItems?.map(tag => )}
+
+
+
+
+
+ >
+}
diff --git a/themes/medium/components/ArticleLock.js b/themes/medium/components/ArticleLock.js
new file mode 100644
index 00000000..aba09687
--- /dev/null
+++ b/themes/medium/components/ArticleLock.js
@@ -0,0 +1,40 @@
+import { useGlobal } from '@/lib/global'
+
+/**
+ * 加密文章校验组件
+ * @param {password, validPassword} props
+ * @param password 正确的密码
+ * @param validPassword(bool) 回调函数,校验正确回调入参为true
+ * @returns
+ */
+export const ArticleLock = props => {
+ const { password, validPassword } = props
+ const { locale } = useGlobal()
+
+ const submitPassword = () => {
+ const p = document.getElementById('password')
+ if (p && p.value && p.value === password) {
+ validPassword(true)
+ } else {
+ const tips = document.getElementById('tips')
+ if (tips) {
+ tips.innerHTML = ''
+ tips.innerHTML = `
${locale.COMMON.PASSWORD_ERROR}
`
+ }
+ }
+ }
+
+ return
+
+
{locale.COMMON.ARTICLE_LOCK_TIPS}
+
+
+
+ {locale.COMMON.SUBMIT}
+
+
+
+
+
+
+}
diff --git a/themes/next/LayoutSlug.js b/themes/next/LayoutSlug.js
index 6a3deaa0..7e555454 100644
--- a/themes/next/LayoutSlug.js
+++ b/themes/next/LayoutSlug.js
@@ -6,11 +6,12 @@ import Card from './components/Card'
import LatestPostsGroup from './components/LatestPostsGroup'
import ArticleDetail from './components/ArticleDetail'
import TocDrawer from './components/TocDrawer'
-import { useRef } from 'react'
+import { useRef, useState } from 'react'
import CONFIG_NEXT from './config_next'
+import { ArticleLock } from './components/ArticleLock'
export const LayoutSlug = (props) => {
- const { post, prev, next, recommendPosts, latestPosts, showArticleInfo } = props
+ const { post, latestPosts } = props
const meta = {
title: `${post.title} | ${BLOG.TITLE}`,
description: post.summary,
@@ -18,12 +19,22 @@ export const LayoutSlug = (props) => {
tags: post.tags
}
- const drawerRight = useRef(null)
- const targetRef = typeof window !== 'undefined' ? document.getElementById('container') : null
- if (post?.blockMap?.block) {
+ // 文章加锁
+ const articleLock = post.password && post.password !== ''
+ const [lock, setLock] = useState(articleLock)
+ const validPassword = result => {
+ if (result) {
+ setLock(false)
+ }
+ }
+
+ if (!lock && post?.blockMap?.block) {
post.content = Object.keys(post.blockMap.block)
post.toc = getPageTableOfContents(post, post.blockMap)
}
+
+ const drawerRight = useRef(null)
+ const targetRef = typeof window !== 'undefined' ? document.getElementById('container') : null
const floatSlot = post?.toc?.length > 1
?
{
drawerRight?.current?.handleSwitchVisible()
@@ -39,13 +50,10 @@ export const LayoutSlug = (props) => {
CONFIG_NEXT.RIGHT_LATEST_POSTS &&
}
>
-
+
+ {!lock && }
+
+ {lock && }
{/* 悬浮目录按钮 */}
diff --git a/themes/next/components/ArticleLock.js b/themes/next/components/ArticleLock.js
new file mode 100644
index 00000000..b8132316
--- /dev/null
+++ b/themes/next/components/ArticleLock.js
@@ -0,0 +1,49 @@
+import { useGlobal } from '@/lib/global'
+
+/**
+ * 加密文章校验组件
+ * @param {password, validPassword} props
+ * @param password 正确的密码
+ * @param validPassword(bool) 回调函数,校验正确回调入参为true
+ * @returns
+ */
+export const ArticleLock = props => {
+ const { password, validPassword } = props
+ const { locale } = useGlobal()
+
+ const submitPassword = () => {
+ const p = document.getElementById('password')
+ if (p && p.value && p.value === password) {
+ validPassword(true)
+ } else {
+ const tips = document.getElementById('tips')
+ if (tips) {
+ tips.innerHTML = ''
+ tips.innerHTML = `
${locale.COMMON.PASSWORD_ERROR}
`
+ }
+ }
+ }
+
+ return (
+
+
+
+
{locale.COMMON.ARTICLE_LOCK_TIPS}
+
+
+
+ {locale.COMMON.SUBMIT}
+
+
+
+
+
+
+ )
+}