Merge pull request #599 from tangly1024/main

发布 tangly1024.com
This commit is contained in:
tangly1024
2022-12-15 11:00:20 +08:00
committed by GitHub
25 changed files with 158 additions and 84 deletions

View File

@@ -1,2 +1,2 @@
# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables
NEXT_PUBLIC_VERSION=3.6.5
NEXT_PUBLIC_VERSION=3.6.6

View File

@@ -14,7 +14,7 @@ import { isIterable } from '../utils'
* @returns {Promise<{}|*[]>}
*/
export function getAllCategories({ allPages, categoryOptions, sliceCount = 0 }) {
const allPosts = allPages.filter(page => page.type === 'Post')
const allPosts = allPages.filter(page => page.type === 'Post' && page.status === 'Published')
if (!allPosts || !categoryOptions) {
return []
}

View File

@@ -8,7 +8,7 @@ import { isIterable } from '../utils'
* @returns {Promise<{}|*[]>}
*/
export function getAllTags({ allPages, sliceCount = 0, tagOptions }) {
const allPosts = allPages.filter(page => page.type === 'Post')
const allPosts = allPages.filter(page => page.type === 'Post' && page.status === 'Published')
if (!allPosts || !tagOptions) {
return []

View File

@@ -212,17 +212,16 @@ async function getPageRecordMapByNotionAPI({ pageId, from }) {
collectionData.push(properties)
}
}
// 读取映射 配置
let postCount = 0
// 获取page作为自定义菜单
const customNav = getCustomNav({ allPages: collectionData.filter(post => post.type === 'Page' && post.status === 'Published') })
// 文章计数
let postCount = 0
const allPages = collectionData.filter(post => {
if (post.type === 'Post' && post.status === 'Published') {
postCount++
}
return post &&
post.type &&
(post.type === 'Post' || post.type === 'Page') &&

View File

@@ -3,6 +3,7 @@ import { NotionAPI } from 'notion-client'
import BLOG from '@/blog.config'
import formatDate from '../formatDate'
import { defaultMapImageUrl } from 'react-notion-x'
import md5 from 'js-md5'
export default async function getPageProperties(id, block, schema, authToken, tagOptions, siteInfo) {
const rawProperties = Object.entries(block?.[id]?.value?.properties || [])
@@ -89,6 +90,7 @@ export default async function getPageProperties(id, block, schema, authToken, ta
properties.pageIcon = getImageUrl(block[id].value?.format?.page_icon, block[id].value) ?? ''
properties.page_cover = getImageUrl(block[id].value?.format?.page_cover, block[id].value) ?? siteInfo?.pageCover
properties.content = value.content ?? []
properties.password = properties.password ? md5(properties.slug + properties.password) : ''
properties.tagItems = properties?.tags?.map(tag => {
return { name: tag, color: tagOptions?.find(t => t.value === tag)?.color || 'gray' }
}) || []

View File

@@ -0,0 +1,90 @@
import { getTextContent } from 'notion-utils'
const indentLevels = {
header: 0,
sub_header: 1,
sub_sub_header: 2
}
/**
* @see https://github.com/NotionX/react-notion-x/blob/master/packages/notion-utils/src/get-page-table-of-contents.ts
* Gets the metadata for a table of contents block by parsing the page's
* H1, H2, and H3 elements.
*/
export const getPageTableOfContents = (page, recordMap) => {
const contents = (page.content ?? [])
const toc = getBlockHeader(contents, recordMap)
const indentLevelStack = [
{
actual: -1,
effective: -1
}
]
// Adjust indent levels to always change smoothly.
// This is a little tricky, but the key is that when increasing indent levels,
// they should never jump more than one at a time.
for (const tocItem of toc) {
const { indentLevel } = tocItem
const actual = indentLevel
do {
const prevIndent = indentLevelStack[indentLevelStack.length - 1]
const { actual: prevActual, effective: prevEffective } = prevIndent
if (actual > prevActual) {
tocItem.indentLevel = prevEffective + 1
indentLevelStack.push({
actual,
effective: tocItem.indentLevel
})
} else if (actual === prevActual) {
tocItem.indentLevel = prevEffective
break
} else {
indentLevelStack.pop()
}
// eslint-disable-next-line no-constant-condition
} while (true)
}
return toc
}
/**
* 重写获取目录方法
*/
function getBlockHeader(contents, recordMap, toc) {
if (!toc) {
toc = []
}
if (!contents) {
return toc
}
for (const blockId of contents) {
const block = recordMap.block[blockId]?.value
if (!block) {
continue
}
const { type } = block
if (type.indexOf('header') >= 0) {
const existed = toc.find(e => e.id === blockId)
if (!existed) {
toc.push({
id: blockId,
type,
text: getTextContent(block.properties?.title),
indentLevel: indentLevels[type]
})
}
}
if (block.content?.length > 0) {
getBlockHeader(block.content, recordMap, toc)
}
}
return toc
}

View File

@@ -1,6 +1,6 @@
{
"name": "notion-next",
"version": "3.6.5",
"version": "3.6.6",
"homepage": "https://github.com/tangly1024/NotionNext.git",
"license": "MIT",
"repository": {
@@ -30,6 +30,7 @@
"eslint-plugin-react-hooks": "^4.6.0",
"feed": "^4.2.2",
"gitalk": "^1.7.2",
"js-md5": "^0.7.3",
"localStorage": "^1.0.4",
"lodash.throttle": "^4.1.1",
"mark.js": "^8.11.1",

View File

@@ -8,6 +8,8 @@ import { idToUuid } from 'notion-utils'
import Router from 'next/router'
import { isBrowser } from '@/lib/utils'
import { getNotion } from '@/lib/notion/getNotion'
import md5 from 'js-md5'
import { getPageTableOfContents } from '@/lib/notion/getPageTableOfContents'
/**
* 根据notion的slug访问页面
@@ -28,6 +30,11 @@ const Slug = props => {
if (post?.password && post?.password !== '') {
setLock(true)
} else {
if (!lock && post?.blockMap?.block) {
post.content = Object.keys(post.blockMap.block)
post.toc = getPageTableOfContents(post, post.blockMap)
}
setLock(false)
}
}, [post])
@@ -51,10 +58,12 @@ const Slug = props => {
* 验证文章密码
* @param {*} result
*/
const validPassword = result => {
if (result) {
const validPassword = passInput => {
if (passInput && md5(post.slug + passInput) === post.password) {
setLock(false)
return true
}
return false
}
props = { ...props, lock, setLock, validPassword }

View File

@@ -191,4 +191,15 @@ nav {
.wl-meta > span {
@apply dark:bg-gray-800 !important
}
/* 固定两行 */
.text-line-2 {
overflow : hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
word-wrap: break-word;
word-break: break-all;
}

View File

@@ -392,7 +392,7 @@
.notion-h {
position: relative;
display: block;
/* display: block; */
font-weight: 600;
line-height: 1.3;
padding: 3px 2px;
@@ -427,7 +427,7 @@
margin-top: 2px;
} */
.notion-h2 {
font-size: 1.5em;
font-size: 1.4em;
margin-top: 1.1em;
}
.notion-h3 {

View File

@@ -1,4 +1,3 @@
import { getPageTableOfContents } from 'notion-utils'
import LayoutBase from './LayoutBase'
import { ArticleLock } from './components/ArticleLock'
import NotionPage from '@/components/NotionPage'
@@ -12,15 +11,10 @@ export const LayoutSlug = props => {
return <LayoutBase {...props} />
}
if (!lock && post?.blockMap?.block) {
post.content = Object.keys(post.blockMap.block)
post.toc = getPageTableOfContents(post, post.blockMap)
}
return (
<LayoutBase {...props}>
{lock && <ArticleLock password={post.password} validPassword={validPassword} />}
{lock && <ArticleLock validPassword={validPassword} />}
{!lock && <div id="notion-article" className="px-2">

View File

@@ -8,14 +8,12 @@ import { useGlobal } from '@/lib/global'
* @returns
*/
export const ArticleLock = props => {
const { password, validPassword } = props
const { validPassword } = props
const { locale } = useGlobal()
const submitPassword = () => {
const p = document.getElementById('password')
if (p && p.value && p.value === password) {
validPassword(true)
} else {
if (!validPassword(p?.value)) {
const tips = document.getElementById('tips')
if (tips) {
tips.innerHTML = ''

View File

@@ -1,19 +1,13 @@
import { getPageTableOfContents } from 'notion-utils'
import ArticleDetail from './components/ArticleDetail'
import LayoutBase from './LayoutBase'
import { ArticleLock } from './components/ArticleLock'
export const LayoutSlug = (props) => {
const { post, lock, validPassword } = props
if (!lock && post?.blockMap?.block) {
post.content = Object.keys(post.blockMap.block)
post.toc = getPageTableOfContents(post, post.blockMap)
}
const { lock, validPassword } = props
return (
<LayoutBase {...props} >
{!lock && <ArticleDetail {...props} />}
{lock && <ArticleLock password={post.password} validPassword={validPassword} />}
{lock && <ArticleLock validPassword={validPassword} />}
</LayoutBase>
)
}

View File

@@ -8,14 +8,12 @@ import { useGlobal } from '@/lib/global'
* @returns
*/
export const ArticleLock = props => {
const { password, validPassword } = props
const { validPassword } = props
const { locale } = useGlobal()
const submitPassword = () => {
const p = document.getElementById('password')
if (p && p.value && p.value === password) {
validPassword(true)
} else {
if (!validPassword(p?.value)) {
const tips = document.getElementById('tips')
if (tips) {
tips.innerHTML = ''

View File

@@ -1,4 +1,3 @@
import { getPageTableOfContents } from 'notion-utils'
import { useRef } from 'react'
import { ArticleLock } from './components/ArticleLock'
import HeaderArticle from './components/HeaderArticle'
@@ -15,6 +14,7 @@ import { isBrowser } from '@/lib/utils'
export const LayoutSlug = props => {
const { post, lock, validPassword } = props
const drawerRight = useRef(null)
if (!post) {
return <LayoutBase
@@ -25,12 +25,6 @@ export const LayoutSlug = props => {
></LayoutBase>
}
if (!lock && post?.blockMap?.block) {
post.content = Object.keys(post.blockMap.block)
post.toc = getPageTableOfContents(post, post.blockMap)
}
const drawerRight = useRef(null)
const targetRef = isBrowser() ? document.getElementById('container') : null
const floatSlot = <>
@@ -53,7 +47,7 @@ export const LayoutSlug = props => {
floatSlot={floatSlot}
>
<div className="w-full lg:shadow-sm lg:hover:shadow lg:border lg:rounded-xl lg:px-2 lg:py-4 bg-white dark:bg-hexo-black-gray dark:border-black">
{lock && <ArticleLock password={post.password} validPassword={validPassword} />}
{lock && <ArticleLock validPassword={validPassword} />}
{!lock && <div id="container" className="overflow-x-auto flex-grow mx-auto md:w-full md:px-5 ">

View File

@@ -8,13 +8,11 @@ import { useGlobal } from '@/lib/global'
* @returns
*/
export const ArticleLock = props => {
const { password, validPassword } = props
const { validPassword } = props
const { locale } = useGlobal()
const submitPassword = () => {
const p = document.getElementById('password')
if (p && p.value && p.value === password) {
validPassword(true)
} else {
if (!validPassword(p?.value)) {
const tips = document.getElementById('tips')
if (tips) {
tips.innerHTML = ''

View File

@@ -4,12 +4,13 @@ import formatDate from '@/lib/formatDate'
import BLOG from '@/blog.config'
export default function HeaderArticle({ post, siteInfo }) {
const { locale } = useGlobal()
if (!post) {
return <></>
}
const headerImage = post?.page_cover ? `url("${post.page_cover}")` : `url("${siteInfo?.pageCover}")`
const { locale } = useGlobal()
const date = formatDate(
post?.date?.start_date || post?.createdTime,
locale.LOCALE

View File

@@ -10,12 +10,14 @@ import { useRouter } from 'next/router'
* @constructor
*/
const LatestPostsGroup = ({ latestPosts, siteInfo }) => {
if (!latestPosts) {
return <></>
}
// 获取当前路径
const currentPath = useRouter().asPath
const { locale } = useGlobal()
if (!latestPosts) {
return <></>
}
return (
<>
<div className=" mb-2 px-1 flex flex-nowrap justify-between">
@@ -37,7 +39,7 @@ const LatestPostsGroup = ({ latestPosts, siteInfo }) => {
href={`${BLOG.SUB_PATH}/${post.slug}`}
passHref
>
<a className={'my-1 flex '}>
<a className={'my-2 flex'}>
<div
className="w-20 h-16 bg-cover bg-center bg-no-repeat"
style={{ backgroundImage: headerImage }}
@@ -45,12 +47,12 @@ const LatestPostsGroup = ({ latestPosts, siteInfo }) => {
<div
className={
(selected ? ' text-indigo-400 ' : 'dark:text-gray-400 ') +
' text-sm py-1.5 overflow-x-hidden hover:text-indigo-600 px-2 duration-200 w-full rounded ' +
' text-sm overflow-x-hidden hover:text-indigo-600 px-2 duration-200 w-full rounded ' +
'hover:text-white dark:hover:text-indigo-400 cursor-pointer items-center flex'
}
>
<div>
<div style={{ WebkitLineClamp: 2 }}>{post.title}</div>
<div className='text-line-2'>{post.title}</div>
<div className="text-gray-500">{post.lastEditedTime}</div>
</div>
</div>

View File

@@ -5,7 +5,7 @@ import BLOG from '@/blog.config'
export const LayoutCategory = props => {
const { category } = props
const slotTop = <div className='flex items-center font-sans p-8'><div className='text-xl'><i className='mr-2 fas fa-th' />分类</div>{category}</div>
const slotTop = <div className='flex items-center font-sans py-8'><div className='text-xl'><i className='mr-2 fas fa-th' />分类</div>{category}</div>
return <LayoutBase {...props} slotTop={slotTop}>
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}

View File

@@ -1,5 +1,3 @@
import { getPageTableOfContents } from 'notion-utils'
import LayoutBase from './LayoutBase'
import { useGlobal } from '@/lib/global'
import React from 'react'
@@ -16,11 +14,6 @@ export const LayoutSlug = props => {
/>
}
if (!lock && post?.blockMap?.block) {
post.content = Object.keys(post.blockMap.block)
post.toc = getPageTableOfContents(post, post.blockMap)
}
const slotRight = post?.toc && post?.toc?.length > 3 && (
<div key={locale.COMMON.TABLE_OF_CONTENTS} >
<Catalog toc={post.toc} />
@@ -29,7 +22,7 @@ export const LayoutSlug = props => {
return (
<LayoutBase showInfoCard={true} slotRight={slotRight} {...props} >
{!lock ? <ArticleDetail {...props} /> : <ArticleLock password={post.password} validPassword={validPassword} />}
{!lock ? <ArticleDetail {...props} /> : <ArticleLock validPassword={validPassword} />}
</LayoutBase>
)
}

View File

@@ -5,7 +5,7 @@ import BlogPostListPage from './components/BlogPostListPage'
export const LayoutTag = (props) => {
const { tag } = props
const slotTop = <div className='flex items-center font-sans p-8'><div className='text-xl'><i className='mr-2 fas fa-tag'/>标签</div>{tag}</div>
const slotTop = <div className='flex items-center font-sans py-8'><div className='text-xl'><i className='mr-2 fas fa-tag'/>标签</div>{tag}</div>
return <LayoutBase {...props} slotTop={slotTop}>
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}

View File

@@ -8,14 +8,12 @@ import { useGlobal } from '@/lib/global'
* @returns
*/
export const ArticleLock = props => {
const { password, validPassword } = props
const { validPassword } = props
const { locale } = useGlobal()
const submitPassword = () => {
const p = document.getElementById('password')
if (p && p.value && p.value === password) {
validPassword(true)
} else {
if (!validPassword(p?.value)) {
const tips = document.getElementById('tips')
if (tips) {
tips.innerHTML = ''

View File

@@ -1,4 +1,3 @@
import { getPageTableOfContents } from 'notion-utils'
import TocDrawerButton from './components/TocDrawerButton'
import LayoutBase from './LayoutBase'
import Card from './components/Card'
@@ -12,11 +11,6 @@ import { isBrowser } from '@/lib/utils'
export const LayoutSlug = (props) => {
const { post, latestPosts, lock, validPassword } = props
if (!lock && post?.blockMap?.block) {
post.content = Object.keys(post.blockMap.block)
post.toc = getPageTableOfContents(post, post.blockMap)
}
const drawerRight = useRef(null)
const targetRef = isBrowser() ? document.getElementById('container') : null
const floatSlot = post?.toc?.length > 1
@@ -45,7 +39,7 @@ export const LayoutSlug = (props) => {
{!lock && <ArticleDetail {...props} />}
{lock && <ArticleLock password={post.password} validPassword={validPassword} />}
{lock && <ArticleLock validPassword={validPassword} />}
{/* 悬浮目录按钮 */}
<div className='block lg:hidden'>

View File

@@ -8,14 +8,12 @@ import { useGlobal } from '@/lib/global'
* @returns
*/
export const ArticleLock = props => {
const { password, validPassword } = props
const { validPassword } = props
const { locale } = useGlobal()
const submitPassword = () => {
const p = document.getElementById('password')
if (p && p.value && p.value === password) {
validPassword(true)
} else {
if (!validPassword(p?.value)) {
const tips = document.getElementById('tips')
if (tips) {
tips.innerHTML = ''

View File

@@ -10,13 +10,14 @@ import { useRouter } from 'next/router'
* @constructor
*/
const LatestPostsGroup = ({ latestPosts }) => {
if (!latestPosts) {
return <></>
}
// 获取当前路径
const currentPath = useRouter().asPath
const { locale } = useGlobal()
if (!latestPosts) {
return <></>
}
return (
<>
<div className="text-sm pb-1 px-2 flex flex-nowrap justify-between">
@@ -40,12 +41,11 @@ const LatestPostsGroup = ({ latestPosts }) => {
(selected
? 'text-white bg-gray-600 '
: 'text-gray-500 dark:text-gray-400 ') +
' text-xs py-1.5 flex overflow-x-hidden whitespace-nowrap hover:bg-gray-500 px-2 duration-200 w-full ' +
' text-xs py-1.5 flex hover:bg-gray-500 px-2 duration-200 w-full ' +
'hover:text-white dark:hover:text-white cursor-pointer'
}
>
<i className="mr-2 fas fa-file-alt" />
<div className="truncate">{post.title}</div>
<li className="text-line-2">{post.title}</li>
</div>
</a>
</Link>