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} -
- {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} +
+ {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} +
+
+
+
+
+
+ ) +}