mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-06-03 07:26:45 +00:00
@@ -1,2 +1,2 @@
|
|||||||
# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables
|
# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables
|
||||||
NEXT_PUBLIC_VERSION=3.6.5
|
NEXT_PUBLIC_VERSION=3.6.6
|
||||||
@@ -14,7 +14,7 @@ import { isIterable } from '../utils'
|
|||||||
* @returns {Promise<{}|*[]>}
|
* @returns {Promise<{}|*[]>}
|
||||||
*/
|
*/
|
||||||
export function getAllCategories({ allPages, categoryOptions, sliceCount = 0 }) {
|
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) {
|
if (!allPosts || !categoryOptions) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { isIterable } from '../utils'
|
|||||||
* @returns {Promise<{}|*[]>}
|
* @returns {Promise<{}|*[]>}
|
||||||
*/
|
*/
|
||||||
export function getAllTags({ allPages, sliceCount = 0, tagOptions }) {
|
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) {
|
if (!allPosts || !tagOptions) {
|
||||||
return []
|
return []
|
||||||
|
|||||||
@@ -212,17 +212,16 @@ async function getPageRecordMapByNotionAPI({ pageId, from }) {
|
|||||||
collectionData.push(properties)
|
collectionData.push(properties)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 读取映射 配置
|
|
||||||
let postCount = 0
|
|
||||||
|
|
||||||
// 获取page作为自定义菜单
|
// 获取page作为自定义菜单
|
||||||
const customNav = getCustomNav({ allPages: collectionData.filter(post => post.type === 'Page' && post.status === 'Published') })
|
const customNav = getCustomNav({ allPages: collectionData.filter(post => post.type === 'Page' && post.status === 'Published') })
|
||||||
|
|
||||||
|
// 文章计数
|
||||||
|
let postCount = 0
|
||||||
const allPages = collectionData.filter(post => {
|
const allPages = collectionData.filter(post => {
|
||||||
if (post.type === 'Post' && post.status === 'Published') {
|
if (post.type === 'Post' && post.status === 'Published') {
|
||||||
postCount++
|
postCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
return post &&
|
return post &&
|
||||||
post.type &&
|
post.type &&
|
||||||
(post.type === 'Post' || post.type === 'Page') &&
|
(post.type === 'Post' || post.type === 'Page') &&
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { NotionAPI } from 'notion-client'
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
import formatDate from '../formatDate'
|
import formatDate from '../formatDate'
|
||||||
import { defaultMapImageUrl } from 'react-notion-x'
|
import { defaultMapImageUrl } from 'react-notion-x'
|
||||||
|
import md5 from 'js-md5'
|
||||||
|
|
||||||
export default async function getPageProperties(id, block, schema, authToken, tagOptions, siteInfo) {
|
export default async function getPageProperties(id, block, schema, authToken, tagOptions, siteInfo) {
|
||||||
const rawProperties = Object.entries(block?.[id]?.value?.properties || [])
|
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.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.page_cover = getImageUrl(block[id].value?.format?.page_cover, block[id].value) ?? siteInfo?.pageCover
|
||||||
properties.content = value.content ?? []
|
properties.content = value.content ?? []
|
||||||
|
properties.password = properties.password ? md5(properties.slug + properties.password) : ''
|
||||||
properties.tagItems = properties?.tags?.map(tag => {
|
properties.tagItems = properties?.tags?.map(tag => {
|
||||||
return { name: tag, color: tagOptions?.find(t => t.value === tag)?.color || 'gray' }
|
return { name: tag, color: tagOptions?.find(t => t.value === tag)?.color || 'gray' }
|
||||||
}) || []
|
}) || []
|
||||||
|
|||||||
90
lib/notion/getPageTableOfContents.js
Normal file
90
lib/notion/getPageTableOfContents.js
Normal 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
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "notion-next",
|
"name": "notion-next",
|
||||||
"version": "3.6.5",
|
"version": "3.6.6",
|
||||||
"homepage": "https://github.com/tangly1024/NotionNext.git",
|
"homepage": "https://github.com/tangly1024/NotionNext.git",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"feed": "^4.2.2",
|
"feed": "^4.2.2",
|
||||||
"gitalk": "^1.7.2",
|
"gitalk": "^1.7.2",
|
||||||
|
"js-md5": "^0.7.3",
|
||||||
"localStorage": "^1.0.4",
|
"localStorage": "^1.0.4",
|
||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
"mark.js": "^8.11.1",
|
"mark.js": "^8.11.1",
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import { idToUuid } from 'notion-utils'
|
|||||||
import Router from 'next/router'
|
import Router from 'next/router'
|
||||||
import { isBrowser } from '@/lib/utils'
|
import { isBrowser } from '@/lib/utils'
|
||||||
import { getNotion } from '@/lib/notion/getNotion'
|
import { getNotion } from '@/lib/notion/getNotion'
|
||||||
|
import md5 from 'js-md5'
|
||||||
|
import { getPageTableOfContents } from '@/lib/notion/getPageTableOfContents'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据notion的slug访问页面
|
* 根据notion的slug访问页面
|
||||||
@@ -28,6 +30,11 @@ const Slug = props => {
|
|||||||
if (post?.password && post?.password !== '') {
|
if (post?.password && post?.password !== '') {
|
||||||
setLock(true)
|
setLock(true)
|
||||||
} else {
|
} else {
|
||||||
|
if (!lock && post?.blockMap?.block) {
|
||||||
|
post.content = Object.keys(post.blockMap.block)
|
||||||
|
post.toc = getPageTableOfContents(post, post.blockMap)
|
||||||
|
}
|
||||||
|
|
||||||
setLock(false)
|
setLock(false)
|
||||||
}
|
}
|
||||||
}, [post])
|
}, [post])
|
||||||
@@ -51,10 +58,12 @@ const Slug = props => {
|
|||||||
* 验证文章密码
|
* 验证文章密码
|
||||||
* @param {*} result
|
* @param {*} result
|
||||||
*/
|
*/
|
||||||
const validPassword = result => {
|
const validPassword = passInput => {
|
||||||
if (result) {
|
if (passInput && md5(post.slug + passInput) === post.password) {
|
||||||
setLock(false)
|
setLock(false)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
props = { ...props, lock, setLock, validPassword }
|
props = { ...props, lock, setLock, validPassword }
|
||||||
|
|||||||
@@ -192,3 +192,14 @@ nav {
|
|||||||
.wl-meta > span {
|
.wl-meta > span {
|
||||||
@apply dark:bg-gray-800 !important
|
@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;
|
||||||
|
}
|
||||||
@@ -392,7 +392,7 @@
|
|||||||
|
|
||||||
.notion-h {
|
.notion-h {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block;
|
/* display: block; */
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
padding: 3px 2px;
|
padding: 3px 2px;
|
||||||
@@ -427,7 +427,7 @@
|
|||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
} */
|
} */
|
||||||
.notion-h2 {
|
.notion-h2 {
|
||||||
font-size: 1.5em;
|
font-size: 1.4em;
|
||||||
margin-top: 1.1em;
|
margin-top: 1.1em;
|
||||||
}
|
}
|
||||||
.notion-h3 {
|
.notion-h3 {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { getPageTableOfContents } from 'notion-utils'
|
|
||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
import { ArticleLock } from './components/ArticleLock'
|
import { ArticleLock } from './components/ArticleLock'
|
||||||
import NotionPage from '@/components/NotionPage'
|
import NotionPage from '@/components/NotionPage'
|
||||||
@@ -12,15 +11,10 @@ export const LayoutSlug = props => {
|
|||||||
return <LayoutBase {...props} />
|
return <LayoutBase {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lock && post?.blockMap?.block) {
|
|
||||||
post.content = Object.keys(post.blockMap.block)
|
|
||||||
post.toc = getPageTableOfContents(post, post.blockMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutBase {...props}>
|
<LayoutBase {...props}>
|
||||||
|
|
||||||
{lock && <ArticleLock password={post.password} validPassword={validPassword} />}
|
{lock && <ArticleLock validPassword={validPassword} />}
|
||||||
|
|
||||||
{!lock && <div id="notion-article" className="px-2">
|
{!lock && <div id="notion-article" className="px-2">
|
||||||
|
|
||||||
|
|||||||
@@ -8,14 +8,12 @@ import { useGlobal } from '@/lib/global'
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const ArticleLock = props => {
|
export const ArticleLock = props => {
|
||||||
const { password, validPassword } = props
|
const { validPassword } = props
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
|
|
||||||
const submitPassword = () => {
|
const submitPassword = () => {
|
||||||
const p = document.getElementById('password')
|
const p = document.getElementById('password')
|
||||||
if (p && p.value && p.value === password) {
|
if (!validPassword(p?.value)) {
|
||||||
validPassword(true)
|
|
||||||
} else {
|
|
||||||
const tips = document.getElementById('tips')
|
const tips = document.getElementById('tips')
|
||||||
if (tips) {
|
if (tips) {
|
||||||
tips.innerHTML = ''
|
tips.innerHTML = ''
|
||||||
|
|||||||
@@ -1,19 +1,13 @@
|
|||||||
import { getPageTableOfContents } from 'notion-utils'
|
|
||||||
import ArticleDetail from './components/ArticleDetail'
|
import ArticleDetail from './components/ArticleDetail'
|
||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
import { ArticleLock } from './components/ArticleLock'
|
import { ArticleLock } from './components/ArticleLock'
|
||||||
|
|
||||||
export const LayoutSlug = (props) => {
|
export const LayoutSlug = (props) => {
|
||||||
const { post, lock, validPassword } = props
|
const { lock, validPassword } = props
|
||||||
if (!lock && post?.blockMap?.block) {
|
|
||||||
post.content = Object.keys(post.blockMap.block)
|
|
||||||
post.toc = getPageTableOfContents(post, post.blockMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutBase {...props} >
|
<LayoutBase {...props} >
|
||||||
{!lock && <ArticleDetail {...props} />}
|
{!lock && <ArticleDetail {...props} />}
|
||||||
{lock && <ArticleLock password={post.password} validPassword={validPassword} />}
|
{lock && <ArticleLock validPassword={validPassword} />}
|
||||||
</LayoutBase>
|
</LayoutBase>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,12 @@ import { useGlobal } from '@/lib/global'
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const ArticleLock = props => {
|
export const ArticleLock = props => {
|
||||||
const { password, validPassword } = props
|
const { validPassword } = props
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
|
|
||||||
const submitPassword = () => {
|
const submitPassword = () => {
|
||||||
const p = document.getElementById('password')
|
const p = document.getElementById('password')
|
||||||
if (p && p.value && p.value === password) {
|
if (!validPassword(p?.value)) {
|
||||||
validPassword(true)
|
|
||||||
} else {
|
|
||||||
const tips = document.getElementById('tips')
|
const tips = document.getElementById('tips')
|
||||||
if (tips) {
|
if (tips) {
|
||||||
tips.innerHTML = ''
|
tips.innerHTML = ''
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { getPageTableOfContents } from 'notion-utils'
|
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
import { ArticleLock } from './components/ArticleLock'
|
import { ArticleLock } from './components/ArticleLock'
|
||||||
import HeaderArticle from './components/HeaderArticle'
|
import HeaderArticle from './components/HeaderArticle'
|
||||||
@@ -15,6 +14,7 @@ import { isBrowser } from '@/lib/utils'
|
|||||||
|
|
||||||
export const LayoutSlug = props => {
|
export const LayoutSlug = props => {
|
||||||
const { post, lock, validPassword } = props
|
const { post, lock, validPassword } = props
|
||||||
|
const drawerRight = useRef(null)
|
||||||
|
|
||||||
if (!post) {
|
if (!post) {
|
||||||
return <LayoutBase
|
return <LayoutBase
|
||||||
@@ -25,12 +25,6 @@ export const LayoutSlug = props => {
|
|||||||
></LayoutBase>
|
></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 targetRef = isBrowser() ? document.getElementById('container') : null
|
||||||
|
|
||||||
const floatSlot = <>
|
const floatSlot = <>
|
||||||
@@ -53,7 +47,7 @@ export const LayoutSlug = props => {
|
|||||||
floatSlot={floatSlot}
|
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">
|
<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 ">
|
{!lock && <div id="container" className="overflow-x-auto flex-grow mx-auto md:w-full md:px-5 ">
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,11 @@ import { useGlobal } from '@/lib/global'
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const ArticleLock = props => {
|
export const ArticleLock = props => {
|
||||||
const { password, validPassword } = props
|
const { validPassword } = props
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
const submitPassword = () => {
|
const submitPassword = () => {
|
||||||
const p = document.getElementById('password')
|
const p = document.getElementById('password')
|
||||||
if (p && p.value && p.value === password) {
|
if (!validPassword(p?.value)) {
|
||||||
validPassword(true)
|
|
||||||
} else {
|
|
||||||
const tips = document.getElementById('tips')
|
const tips = document.getElementById('tips')
|
||||||
if (tips) {
|
if (tips) {
|
||||||
tips.innerHTML = ''
|
tips.innerHTML = ''
|
||||||
|
|||||||
@@ -4,12 +4,13 @@ import formatDate from '@/lib/formatDate'
|
|||||||
import BLOG from '@/blog.config'
|
import BLOG from '@/blog.config'
|
||||||
|
|
||||||
export default function HeaderArticle({ post, siteInfo }) {
|
export default function HeaderArticle({ post, siteInfo }) {
|
||||||
|
const { locale } = useGlobal()
|
||||||
|
|
||||||
if (!post) {
|
if (!post) {
|
||||||
return <></>
|
return <></>
|
||||||
}
|
}
|
||||||
const headerImage = post?.page_cover ? `url("${post.page_cover}")` : `url("${siteInfo?.pageCover}")`
|
const headerImage = post?.page_cover ? `url("${post.page_cover}")` : `url("${siteInfo?.pageCover}")`
|
||||||
|
|
||||||
const { locale } = useGlobal()
|
|
||||||
const date = formatDate(
|
const date = formatDate(
|
||||||
post?.date?.start_date || post?.createdTime,
|
post?.date?.start_date || post?.createdTime,
|
||||||
locale.LOCALE
|
locale.LOCALE
|
||||||
|
|||||||
@@ -10,12 +10,14 @@ import { useRouter } from 'next/router'
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
const LatestPostsGroup = ({ latestPosts, siteInfo }) => {
|
const LatestPostsGroup = ({ latestPosts, siteInfo }) => {
|
||||||
if (!latestPosts) {
|
|
||||||
return <></>
|
|
||||||
}
|
|
||||||
// 获取当前路径
|
// 获取当前路径
|
||||||
const currentPath = useRouter().asPath
|
const currentPath = useRouter().asPath
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
|
|
||||||
|
if (!latestPosts) {
|
||||||
|
return <></>
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className=" mb-2 px-1 flex flex-nowrap justify-between">
|
<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}`}
|
href={`${BLOG.SUB_PATH}/${post.slug}`}
|
||||||
passHref
|
passHref
|
||||||
>
|
>
|
||||||
<a className={'my-1 flex '}>
|
<a className={'my-2 flex'}>
|
||||||
<div
|
<div
|
||||||
className="w-20 h-16 bg-cover bg-center bg-no-repeat"
|
className="w-20 h-16 bg-cover bg-center bg-no-repeat"
|
||||||
style={{ backgroundImage: headerImage }}
|
style={{ backgroundImage: headerImage }}
|
||||||
@@ -45,12 +47,12 @@ const LatestPostsGroup = ({ latestPosts, siteInfo }) => {
|
|||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
(selected ? ' text-indigo-400 ' : 'dark:text-gray-400 ') +
|
(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'
|
'hover:text-white dark:hover:text-indigo-400 cursor-pointer items-center flex'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div>
|
<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 className="text-gray-500">{post.lastEditedTime}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import BLOG from '@/blog.config'
|
|||||||
|
|
||||||
export const LayoutCategory = props => {
|
export const LayoutCategory = props => {
|
||||||
const { category } = 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}>
|
return <LayoutBase {...props} slotTop={slotTop}>
|
||||||
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
|
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { getPageTableOfContents } from 'notion-utils'
|
|
||||||
|
|
||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
import { useGlobal } from '@/lib/global'
|
import { useGlobal } from '@/lib/global'
|
||||||
import React from 'react'
|
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 && (
|
const slotRight = post?.toc && post?.toc?.length > 3 && (
|
||||||
<div key={locale.COMMON.TABLE_OF_CONTENTS} >
|
<div key={locale.COMMON.TABLE_OF_CONTENTS} >
|
||||||
<Catalog toc={post.toc} />
|
<Catalog toc={post.toc} />
|
||||||
@@ -29,7 +22,7 @@ export const LayoutSlug = props => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutBase showInfoCard={true} slotRight={slotRight} {...props} >
|
<LayoutBase showInfoCard={true} slotRight={slotRight} {...props} >
|
||||||
{!lock ? <ArticleDetail {...props} /> : <ArticleLock password={post.password} validPassword={validPassword} />}
|
{!lock ? <ArticleDetail {...props} /> : <ArticleLock validPassword={validPassword} />}
|
||||||
</LayoutBase>
|
</LayoutBase>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import BlogPostListPage from './components/BlogPostListPage'
|
|||||||
|
|
||||||
export const LayoutTag = (props) => {
|
export const LayoutTag = (props) => {
|
||||||
const { tag } = 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}>
|
return <LayoutBase {...props} slotTop={slotTop}>
|
||||||
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
|
{BLOG.POST_LIST_STYLE === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
|
||||||
|
|||||||
@@ -8,14 +8,12 @@ import { useGlobal } from '@/lib/global'
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const ArticleLock = props => {
|
export const ArticleLock = props => {
|
||||||
const { password, validPassword } = props
|
const { validPassword } = props
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
|
|
||||||
const submitPassword = () => {
|
const submitPassword = () => {
|
||||||
const p = document.getElementById('password')
|
const p = document.getElementById('password')
|
||||||
if (p && p.value && p.value === password) {
|
if (!validPassword(p?.value)) {
|
||||||
validPassword(true)
|
|
||||||
} else {
|
|
||||||
const tips = document.getElementById('tips')
|
const tips = document.getElementById('tips')
|
||||||
if (tips) {
|
if (tips) {
|
||||||
tips.innerHTML = ''
|
tips.innerHTML = ''
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { getPageTableOfContents } from 'notion-utils'
|
|
||||||
import TocDrawerButton from './components/TocDrawerButton'
|
import TocDrawerButton from './components/TocDrawerButton'
|
||||||
import LayoutBase from './LayoutBase'
|
import LayoutBase from './LayoutBase'
|
||||||
import Card from './components/Card'
|
import Card from './components/Card'
|
||||||
@@ -12,11 +11,6 @@ import { isBrowser } from '@/lib/utils'
|
|||||||
|
|
||||||
export const LayoutSlug = (props) => {
|
export const LayoutSlug = (props) => {
|
||||||
const { post, latestPosts, lock, validPassword } = 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 drawerRight = useRef(null)
|
||||||
const targetRef = isBrowser() ? document.getElementById('container') : null
|
const targetRef = isBrowser() ? document.getElementById('container') : null
|
||||||
const floatSlot = post?.toc?.length > 1
|
const floatSlot = post?.toc?.length > 1
|
||||||
@@ -45,7 +39,7 @@ export const LayoutSlug = (props) => {
|
|||||||
|
|
||||||
{!lock && <ArticleDetail {...props} />}
|
{!lock && <ArticleDetail {...props} />}
|
||||||
|
|
||||||
{lock && <ArticleLock password={post.password} validPassword={validPassword} />}
|
{lock && <ArticleLock validPassword={validPassword} />}
|
||||||
|
|
||||||
{/* 悬浮目录按钮 */}
|
{/* 悬浮目录按钮 */}
|
||||||
<div className='block lg:hidden'>
|
<div className='block lg:hidden'>
|
||||||
|
|||||||
@@ -8,14 +8,12 @@ import { useGlobal } from '@/lib/global'
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const ArticleLock = props => {
|
export const ArticleLock = props => {
|
||||||
const { password, validPassword } = props
|
const { validPassword } = props
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
|
|
||||||
const submitPassword = () => {
|
const submitPassword = () => {
|
||||||
const p = document.getElementById('password')
|
const p = document.getElementById('password')
|
||||||
if (p && p.value && p.value === password) {
|
if (!validPassword(p?.value)) {
|
||||||
validPassword(true)
|
|
||||||
} else {
|
|
||||||
const tips = document.getElementById('tips')
|
const tips = document.getElementById('tips')
|
||||||
if (tips) {
|
if (tips) {
|
||||||
tips.innerHTML = ''
|
tips.innerHTML = ''
|
||||||
|
|||||||
@@ -10,13 +10,14 @@ import { useRouter } from 'next/router'
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
const LatestPostsGroup = ({ latestPosts }) => {
|
const LatestPostsGroup = ({ latestPosts }) => {
|
||||||
if (!latestPosts) {
|
|
||||||
return <></>
|
|
||||||
}
|
|
||||||
// 获取当前路径
|
// 获取当前路径
|
||||||
const currentPath = useRouter().asPath
|
const currentPath = useRouter().asPath
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
|
|
||||||
|
if (!latestPosts) {
|
||||||
|
return <></>
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="text-sm pb-1 px-2 flex flex-nowrap justify-between">
|
<div className="text-sm pb-1 px-2 flex flex-nowrap justify-between">
|
||||||
@@ -40,12 +41,11 @@ const LatestPostsGroup = ({ latestPosts }) => {
|
|||||||
(selected
|
(selected
|
||||||
? 'text-white bg-gray-600 '
|
? 'text-white bg-gray-600 '
|
||||||
: 'text-gray-500 dark:text-gray-400 ') +
|
: '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'
|
'hover:text-white dark:hover:text-white cursor-pointer'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<i className="mr-2 fas fa-file-alt" />
|
<li className="text-line-2">{post.title}</li>
|
||||||
<div className="truncate">{post.title}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
Reference in New Issue
Block a user