Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
actions-user committed Jan 31, 2024
2 parents 55af22e + 003b358 commit fa3c6f8
Show file tree
Hide file tree
Showing 43 changed files with 621 additions and 519 deletions.
6 changes: 3 additions & 3 deletions .env.local
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables
NEXT_PUBLIC_VERSION=4.2.0
NEXT_PUBLIC_VERSION=4.2.1


# 可在此添加环境变量,去掉最左边的(# )注释即可
# Notion页面ID,必须
# NOTION_PAGE_ID=
# NOTION_PAGE_ID=097e5f674880459d8e1b4407758dc4fb

# 非必须
# NEXT_PUBLIC_PSEUDO_STATIC=
# NEXT_PUBLIC_REVALIDATE_SECOND=
# NEXT_PUBLIC_THEME=
# NEXT_PUBLIC_THEME=matery
# NEXT_PUBLIC_THEME_SWITCH=
# NEXT_PUBLIC_LANG=
# NEXT_PUBLIC_APPEARANCE=
Expand Down
3 changes: 3 additions & 0 deletions blog.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,9 @@ const BLOG = {
SEO_BAIDU_SITE_VERIFICATION:
process.env.NEXT_PUBLIC_SEO_BAIDU_SITE_VERIFICATION || '', // Remove the value or replace it with your own google site verification code

// 微软 Clarity 站点分析
CLARITY_ID: process.env.NEXT_PUBLIC_CLARITY_ID || null , // 只需要复制Clarity脚本中的ID部分,ID是一个十位的英文数字组合

// <---- 站点统计

// START---->营收相关
Expand Down
8 changes: 4 additions & 4 deletions components/Busuanzi.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ import busuanzi from '@/lib/busuanzi'
import { useRouter } from 'next/router'
import { useGlobal } from '@/lib/global'
// import { useRouter } from 'next/router'
import React from 'react'
import { useEffect } from 'react'

let path = ''

export default function Busuanzi () {
const { theme } = useGlobal()
const Router = useRouter()
Router.events.on('routeChangeComplete', (url, option) => {
const router = useRouter()
router.events.on('routeChangeComplete', (url, option) => {
if (url !== path) {
path = url
busuanzi.fetch()
}
})

// 更换主题时更新
React.useEffect(() => {
useEffect(() => {
if (theme) {
busuanzi.fetch()
}
Expand Down
13 changes: 13 additions & 0 deletions components/ExternalPlugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const ExternalPlugin = (props) => {
const DIFY_CHATBOT_ENABLED = siteConfig('DIFY_CHATBOT_ENABLED')
const TIANLI_KEY = siteConfig('TianliGPT_KEY')
const GLOBAL_JS = siteConfig('GLOBAL_JS')
const CLARITY_ID = siteConfig('CLARITY_ID')

// 自定义样式css和js引入
if (isBrowser) {
Expand Down Expand Up @@ -167,6 +168,18 @@ const ExternalPlugin = (props) => {
}} />
</>)}

{CLARITY_ID && (<>
<script async dangerouslySetInnerHTML={{
__html: `
(function(c,l,a,r,i,t,y){
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", "${CLARITY_ID}");
`
}} />
</>)}

{COMMENT_DAO_VOICE_ID && (<>
{/* DaoVoice 反馈 */}
<script async dangerouslySetInnerHTML={{
Expand Down
55 changes: 39 additions & 16 deletions components/Twikoo.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { siteConfig } from '@/lib/config'
// import { loadExternalResource } from '@/lib/utils'
import { useEffect } from 'react'
import { loadExternalResource } from '@/lib/utils'
import { useEffect, useRef, useState } from 'react'

/**
* Giscus评论 @see https://giscus.app/zh-CN
Expand All @@ -12,23 +12,46 @@ import { useEffect } from 'react'
const Twikoo = ({ isDarkMode }) => {
const envId = siteConfig('COMMENT_TWIKOO_ENV_ID')
const el = siteConfig('COMMENT_TWIKOO_ELEMENT_ID', '#twikoo')

const twikooCDNURL = siteConfig('COMMENT_TWIKOO_CDN_URL')
const lang = siteConfig('LANG')
useEffect(() => {
const twikoo = window?.twikoo
if (typeof twikoo !== 'undefined' && twikoo && typeof twikoo.init === 'function') {
twikoo.init({
envId: envId, // 腾讯云环境填 envId;Vercel 环境填地址(https://xxx.vercel.app)
el: el, // 容器元素
lang: lang // 用于手动设定评论区语言,支持的语言列表 https://github.com/imaegoo/twikoo/blob/main/src/client/utils/i18n/index.js
// region: 'ap-guangzhou', // 环境地域,默认为 ap-shanghai,腾讯云环境填 ap-shanghai 或 ap-guangzhou;Vercel 环境不填
// path: location.pathname, // 用于区分不同文章的自定义 js 路径,如果您的文章路径不是 location.pathname,需传此参数
})
const [isInit] = useState(useRef(false))

const loadTwikoo = async () => {
try {
await loadExternalResource(twikooCDNURL, 'js')
const twikoo = window?.twikoo
if (
typeof twikoo !== 'undefined' &&
twikoo &&
typeof twikoo.init === 'function'
) {
twikoo.init({
envId: envId, // 腾讯云环境填 envId;Vercel 环境填地址(https://xxx.vercel.app)
el: el, // 容器元素
lang: lang // 用于手动设定评论区语言,支持的语言列表 https://github.com/imaegoo/twikoo/blob/main/src/client/utils/i18n/index.js
// region: 'ap-guangzhou', // 环境地域,默认为 ap-shanghai,腾讯云环境填 ap-shanghai 或 ap-guangzhou;Vercel 环境不填
// path: location.pathname, // 用于区分不同文章的自定义 js 路径,如果您的文章路径不是 location.pathname,需传此参数
})
console.log('twikoo init', twikoo)
isInit.current = true
}
} catch (error) {
console.error('twikoo 加载失败', error)
}
}

useEffect(() => {
const interval = setInterval(() => {
if (isInit.current) {
console.log('twioo init! clear interval')
clearInterval(interval)
} else {
loadTwikoo()
}
}, 1000)
return () => clearInterval(interval)
}, [isDarkMode])
return (
<div id="twikoo"></div>
)
return <div id="twikoo"></div>
}

export default Twikoo
7 changes: 5 additions & 2 deletions components/Utterances.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ const Utterances = ({ issueTerm, layout }) => {
const [isLoading, setLoading] = useState(true);

useEffect(() => {
const script = document.createElement('script');
const anchor = document.getElementById('comments');
if (!anchor) {
return
}
const script = document.createElement('script');
script.onload = () => setLoading(false);
script.setAttribute('src', 'https://utteranc.es/client.js');
script.setAttribute('crossorigin', 'anonymous');
Expand All @@ -25,7 +28,7 @@ const Utterances = ({ issueTerm, layout }) => {
script.setAttribute('issue-term', 'title');
// 初始主题
script.setAttribute('theme', isDarkMode ? 'github-dark' : 'github-light');
anchor.appendChild(script);
anchor?.appendChild(script);

return () => {
// anchor.innerHTML = ''
Expand Down
33 changes: 33 additions & 0 deletions hooks/useAdjustStyle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { isBrowser } from '@/lib/utils';
import { useEffect } from 'react';

const useAdjustStyle = () => {
/**
* 避免 callout 含有图片时溢出撑开父容器
*/
const adjustCalloutImg = () => {
const callOuts = document.querySelectorAll('.notion-callout-text');
callOuts.forEach((callout) => {
const images = callout.querySelectorAll('figure.notion-asset-wrapper.notion-asset-wrapper-image > div');
const calloutWidth = callout.offsetWidth;
images.forEach((container) => {
const imageWidth = container.offsetWidth;
if (imageWidth + 50 > calloutWidth) {
container.style.setProperty('width', '100%');
}
});
});
};

useEffect(() => {
if (isBrowser) {
adjustCalloutImg();
window.addEventListener('resize', adjustCalloutImg);
return () => {
window.removeEventListener('resize', adjustCalloutImg);
};
}
}, []);
};

export default useAdjustStyle;
2 changes: 1 addition & 1 deletion lib/notion/getAllPosts.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export async function getAllPosts({ notionPageData, from, pageType }) {
if (!value) {
continue
}
const properties = (await getPageProperties(id, block, schema, null, tagOptions)) || null
const properties = (await getPageProperties(id, block[id].value, schema, null, tagOptions)) || null
data.push(properties)
}

Expand Down
48 changes: 41 additions & 7 deletions lib/notion/getNotionData.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import BLOG from '@/blog.config'
import { getDataFromCache, setDataToCache } from '@/lib/cache/cache_manager'
import { getPostBlocks } from '@/lib/notion/getPostBlocks'
import { getPostBlocks, getSingleBlock } from '@/lib/notion/getPostBlocks'
import { idToUuid } from 'notion-utils'
import { deepClone } from '../utils'
import { getAllCategories } from './getAllCategories'
Expand Down Expand Up @@ -185,7 +185,17 @@ export function getNavPages({ allPages }) {
return post && post?.slug && (!post?.slug?.startsWith('http')) && post?.type === 'Post' && post?.status === 'Published'
})

return allNavPages.map(item => ({ id: item.id, title: item.title || '', pageCoverThumbnail: item.pageCoverThumbnail || '', category: item.category || null, tags: item.tags || null, summary: item.summary || null, slug: item.slug, pageIcon: item.pageIcon || '', lastEditedDate: item.lastEditedDate }))
return allNavPages.map(item => ({
id: item.id,
title: item.title || '',
pageCoverThumbnail: item.pageCoverThumbnail || '',
category: item.category || null,
tags: item.tags || null,
summary: item.summary || null,
slug: item.slug,
pageIcon: item.pageIcon || '',
lastEditedDate: item.lastEditedDate
}))
}

/**
Expand All @@ -205,7 +215,15 @@ const EmptyData = (pageId) => {
const empty = {
notice: null,
siteInfo: getSiteInfo({}),
allPages: [{ id: 1, title: `无法获取Notion数据,请检查Notion_ID: \n 当前 ${pageId}`, summary: '访问文档获取帮助→ https://tangly1024.com/article/vercel-deploy-notion-next', status: 'Published', type: 'Post', slug: '13a171332816461db29d50e9f575b00d', date: { start_date: '2023-04-24', lastEditedDay: '2023-04-24', tagItems: [] } }],
allPages: [{
id: 1,
title: `无法获取Notion数据,请检查Notion_ID: \n 当前 ${pageId}`,
summary: '访问文档获取帮助→ https://tangly1024.com/article/vercel-deploy-notion-next',
status: 'Published',
type: 'Post',
slug: '13a171332816461db29d50e9f575b00d',
date: { start_date: '2023-04-24', lastEditedDay: '2023-04-24', tagItems: [] }
}],
allNavPages: [],
collection: [],
collectionQuery: {},
Expand Down Expand Up @@ -255,17 +273,31 @@ async function getDataBaseInfoByNotionAPI({ pageId, from }) {

const viewIds = rawMetadata?.view_ids
const collectionData = []

const pageIds = getAllPageIds(collectionQuery, collectionId, collectionView, viewIds)
if (pageIds?.length === 0) {
console.error('获取到的文章列表为空,请检查notion模板', collectionQuery, collection, collectionView, viewIds, pageRecordMap)
} else {
console.log('有效Page数量', pageIds?.length)
}

// 获取每篇文章基础数据
for (let i = 0; i < pageIds.length; i++) {
const id = pageIds[i]
const value = block[id]?.value
if (!value) {
// 如果找不到文章对应的block,说明发生了溢出,使用pageID再去请求
const pageBlock = await getSingleBlock(id, from)
if (pageBlock.block[id].value) {
const properties = (await getPageProperties(id, pageBlock.block[id].value, schema, null, getTagOptions(schema))) || null
if (properties) {
collectionData.push(properties)
}
}
continue
}
const properties = (await getPageProperties(id, block, schema, null, getTagOptions(schema))) || null

const properties = (await getPageProperties(id, value, schema, null, getTagOptions(schema))) || null
if (properties) {
collectionData.push(properties)
}
Expand All @@ -280,8 +312,8 @@ async function getDataBaseInfoByNotionAPI({ pageId, from }) {
postCount++
}
return post && post?.slug &&
(!post?.slug?.startsWith('http')) &&
(post?.status === 'Invisible' || post?.status === 'Published')
(!post?.slug?.startsWith('http')) &&
(post?.status === 'Invisible' || post?.status === 'Published')
})

// 站点配置优先读取配置表格,否则读取blog.config.js 文件
Expand All @@ -294,7 +326,9 @@ async function getDataBaseInfoByNotionAPI({ pageId, from }) {
})
}

const notice = await getNotice(collectionData.filter(post => { return post && post?.type && post?.type === 'Notice' && post.status === 'Published' })?.[0])
const notice = await getNotice(collectionData.filter(post => {
return post && post?.type && post?.type === 'Notice' && post.status === 'Published'
})?.[0])
const categoryOptions = getAllCategories({ allPages, categoryOptions: getCategoryOptions(schema) })
const tagOptions = getAllTags({ allPages, tagOptions: getTagOptions(schema) })
// 旧的菜单
Expand Down
20 changes: 10 additions & 10 deletions lib/notion/getPageProperties.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,15 @@ import { mapImgUrl } from './mapImage'
/**
* 获取页面元素成员属性
* @param {*} id
* @param {*} block
* @param {*} value
* @param {*} schema
* @param {*} authToken
* @param {*} tagOptions
* @returns
*/
export default async function getPageProperties(id, block, schema, authToken, tagOptions) {
const rawProperties = Object.entries(block?.[id]?.value?.properties || [])
export default async function getPageProperties(id, value, schema, authToken, tagOptions) {
const rawProperties = Object.entries(value?.properties || [])
const excludeProperties = ['date', 'select', 'multi_select', 'person']
const value = block[id]?.value
const properties = {}
for (let i = 0; i < rawProperties.length; i++) {
const [key, val] = rawProperties[i]
Expand Down Expand Up @@ -91,21 +90,22 @@ export default async function getPageProperties(id, block, schema, authToken, ta
properties.lastEditedDate = new Date(value?.last_edited_time)
properties.lastEditedDay = formatDate(new Date(value?.last_edited_time), BLOG.LANG)
properties.fullWidth = value.format?.page_full_width ?? false
properties.pageIcon = mapImgUrl(block[id].value?.format?.page_icon, block[id].value) ?? ''
properties.pageCover = mapImgUrl(block[id].value?.format?.page_cover, block[id].value) ?? ''
properties.pageCoverThumbnail = mapImgUrl(block[id].value?.format?.page_cover, block[id].value, 'block', 'pageCoverThumbnail') ?? ''
properties.pageIcon = mapImgUrl(value?.format?.page_icon, value) ?? ''
properties.pageCover = mapImgUrl(value?.format?.page_cover, value) ?? ''
properties.pageCoverThumbnail = mapImgUrl(value?.format?.page_cover, value, 'block', 'pageCoverThumbnail') ?? ''

properties.content = value.content ?? []
properties.tagItems = properties?.tags?.map(tag => {
return { name: tag, color: tagOptions?.find(t => t.value === tag)?.color || 'gray' }
}) || []
delete properties.content

// 处理URL
if (properties.type === BLOG.NOTION_PROPERTY_NAME.type_post) {
if (properties.type === 'Post') {
properties.slug = (BLOG.POST_URL_PREFIX) ? generateCustomizeUrl(properties) : (properties.slug ?? properties.id)
} else if (properties.type === BLOG.NOTION_PROPERTY_NAME.type_page) {
} else if (properties.type === 'Page') {
properties.slug = properties.slug ?? properties.id
} else if (properties.type === BLOG.NOTION_PROPERTY_NAME.type_menu || properties.type === BLOG.NOTION_PROPERTY_NAME.type_sub_menu) {
} else if (properties.type === 'Menu' || properties.type === 'SubMenu') {
// 菜单路径为空、作为可展开菜单使用
properties.to = properties.slug ?? '#'
properties.name = properties.title ?? ''
Expand Down
20 changes: 20 additions & 0 deletions lib/notion/getPostBlocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,25 @@ export async function getPostBlocks(id, from, slice) {
return pageBlock
}

export async function getSingleBlock(id, from) {
const cacheKey = 'single_block_' + id
let pageBlock = await getDataFromCache(cacheKey)
if (pageBlock) {
console.log('[缓存]:', `from:${from}`, cacheKey)
return pageBlock
}

const start = new Date().getTime()
pageBlock = await getPageWithRetry(id, from)
const end = new Date().getTime()
console.log('[API耗时]', `${end - start}ms`)

if (pageBlock) {
await setDataToCache(cacheKey, pageBlock)
}
return pageBlock
}

/**
* 调用接口,失败会重试
* @param {*} id
Expand All @@ -42,6 +61,7 @@ export async function getPageWithRetry(id, from, retryAttempts = 3) {
const authToken = BLOG.NOTION_ACCESS_TOKEN || null
const api = new NotionAPI({ authToken, userTimeZone: Intl.DateTimeFormat().resolvedOptions().timeZone })
const pageData = await api.getPage(id)
// console.log('stringfy', JSON.stringify(pageData))
console.info('[响应成功]:', `from:${from}`)
return pageData
} catch (e) {
Expand Down
Loading

0 comments on commit fa3c6f8

Please sign in to comment.