+ {/* 主题切换按钮 */}
+
+
+
+
+
-
+
- {/* 切换主题加载时的全屏遮罩 */}
-
-
+ {/* 深色按钮 */}
+
+
+
+ {isDarkMode ? locale.MENU.DARK_MODE : locale.MENU.LIGHT_MODE}
+
+
+
+ {/* 翻译按钮 */}
+
+
+
+
+
+
+
+
+
+ {/* 切换主题加载时的全屏遮罩 */}
+
+
+
>
)
}
diff --git a/lib/config.js b/lib/config.js
index 478bf84e..b4f70e82 100644
--- a/lib/config.js
+++ b/lib/config.js
@@ -2,7 +2,7 @@
import BLOG from '@/blog.config'
import { useGlobal } from './global'
-import { deepClone } from './utils'
+import { deepClone, isUrl } from './utils'
/**
* 读取配置顺序
@@ -19,7 +19,7 @@ export const siteConfig = (key, defaultVal = null, extendConfig = {}) => {
return null
}
- // 特殊配置处理;某些配置只在服务端生效;而Global的NOTION_CONFIG仅限前端组件使用,因此需要从extendConfig中读取
+ // 特殊配置处理;以下配置只在服务端生效;而Global的NOTION_CONFIG仅限前端组件使用,因此需要从extendConfig中读取
switch (key) {
case 'NEXT_REVALIDATE_SECOND':
case 'POST_RECOMMEND_COUNT':
@@ -32,6 +32,8 @@ export const siteConfig = (key, defaultVal = null, extendConfig = {}) => {
case 'POST_LIST_STYLE':
case 'POST_LIST_PREVIEW':
case 'POST_URL_PREFIX_MAPPING_CATEGORY':
+ case 'IS_TAG_COLOR_DISTINGUISHED':
+ case 'TAG_SORT_BY_COUNT':
return convertVal(extendConfig[key] || defaultVal || BLOG[key])
default:
}
@@ -53,8 +55,8 @@ export const siteConfig = (key, defaultVal = null, extendConfig = {}) => {
let siteInfo = null
if (global) {
- val = global.NOTION_CONFIG?.[key]
siteInfo = global.siteInfo
+ val = global.NOTION_CONFIG?.[key] || global.THEME_CONFIG?.[key]
}
if (!val) {
@@ -89,46 +91,62 @@ export const siteConfig = (key, defaultVal = null, extendConfig = {}) => {
return defaultVal
}
- // 从Notion_CONFIG读取的配置通常都是字符串,适当转义
return convertVal(val)
}
/**
- * 配置默认都是string类型;
- * 识别配置的值是否数字、布尔、[]数组,若是则转成对应类型
+ * 从环境变量和NotionConfig读取的配置都是string类型;
+ * 这里识别出配置的字符值若为否 数字、布尔、[]数组,{}对象,若是则转成对应类型
+ * 使用JSON和eval两个函数
* @param {*} val
* @returns
*/
export const convertVal = val => {
- if (typeof val === 'string') {
- // 解析布尔
- if (val === 'true' || val === 'false') {
- return JSON.parse(val)
- }
-
- // 解析数字,parseInt将字符串转换为数字
- if (/^\d+$/.test(val)) {
- return parseInt(val)
- }
- // 转移 [] , {} 这种json串为json对象
- try {
- const parsedJson = JSON.parse(val)
- // 检查解析后的结果是否是对象或数组
- if (typeof parsedJson === 'object' && parsedJson !== null) {
- return parsedJson
- }
- } catch (error) {
- // JSON 解析失败,返回原始字符串值
- return val
- }
- }
-
- try {
- return JSON.parse(val)
- } catch (error) {
- // 如果值是一个字符串但不是有效的 JSON 格式,直接返回字符串
+ // 如果传入参数本身就是obj、数组、boolean 就无需处理
+ if (typeof val !== 'string' || !val) {
return val
}
+
+ // 解析数字,parseInt将字符串转换为数字
+ if (/^\d+$/.test(val)) {
+ return parseInt(val)
+ }
+
+ // 检测是否url
+ if (isUrl(val)) {
+ return val
+ }
+ // 检测是否url
+ if (val === 'true' || val === 'false') {
+ return JSON.parse(val)
+ }
+
+ // 配置值前可能有污染的空格
+ if (val.indexOf('[') < 0 && val.indexOf('{') < 0) {
+ return val
+ }
+
+ // 转换 [] , {} , true/false 这类字符串为对象
+ try {
+ // 尝试解析json
+ const parsedJson = JSON.parse(val)
+ if (parsedJson !== null) {
+ return parsedJson
+ }
+ } catch (error) {
+ // try {
+ // // 尝试解析对象,对象解析能力不如上一步的json
+ // const evalObj = eval('(' + val + ')')
+ // if (evalObj !== null) {
+ // return evalObj
+ // }
+ // } catch (error) {
+ // // Ojbject 解析失败,返回原始字符串值
+ // return val
+ // }
+ return val
+ }
+ return val
}
/**
diff --git a/lib/db/getSiteData.js b/lib/db/getSiteData.js
index 272c17f1..48de0f27 100755
--- a/lib/db/getSiteData.js
+++ b/lib/db/getSiteData.js
@@ -5,18 +5,18 @@ import getAllPageIds from '@/lib/notion/getAllPageIds'
import { getAllTags } from '@/lib/notion/getAllTags'
import { getConfigMapFromConfigPage } from '@/lib/notion/getNotionConfig'
import getPageProperties, {
- adjustPageProperties
+ adjustPageProperties
} from '@/lib/notion/getPageProperties'
-import { fetchInBatches, getPostBlocks } from '@/lib/notion/getPostBlocks'
+import { fetchInBatches, getPage } from '@/lib/notion/getPostBlocks'
import { compressImage, mapImgUrl } from '@/lib/notion/mapImage'
import { deepClone } from '@/lib/utils'
import { idToUuid } from 'notion-utils'
import { siteConfig } from '../config'
-import { extractLangId, extractLangPrefix } from '../utils/pageId'
+import { extractLangId, extractLangPrefix, getShortId } from '../utils/pageId'
export { getAllTags } from '../notion/getAllTags'
export { getPost } from '../notion/getNotionPost'
-export { getPostBlocks } from '../notion/getPostBlocks'
+export { getPage as getPostBlocks } from '../notion/getPostBlocks'
/**
* 获取博客数据; 基于Notion实现
@@ -77,7 +77,18 @@ export async function getNotionPageData({ pageId, from }) {
}
// 返回给前端的数据做处理
- const db = deepClone(data)
+ return handleDataBeforeReturn(deepClone(data))
+}
+
+/**
+ * 返回给浏览器前端的数据处理
+ * 适当脱敏
+ * 减少体积
+ * 其它处理
+ * @param {*} db
+ */
+function handleDataBeforeReturn(db) {
+ // 清理多余数据
delete db.block
delete db.schema
delete db.rawMetadata
@@ -91,42 +102,88 @@ export async function getNotionPageData({ pageId, from }) {
// 清理多余的块
if (db?.notice) {
db.notice = cleanBlock(db?.notice)
+ delete db.notice?.id
}
- if (db?.post) {
- db.post = cleanBlock(db?.post)
- }
+
+ db.tagOptions = cleanIds(db?.tagOptions)
+ db.categoryOptions = cleanIds(db?.categoryOptions)
+ db.customMenu = cleanIds(db?.customMenu)
+
+ // db.latestPosts = shortenIds(db?.latestPosts)
+ db.allNavPages = shortenIds(db?.allNavPages)
+ // db.allPages = cleanBlocks(db?.allPages)
+
return db
}
+/**
+ * 清理一组数据的id
+ * @param {*} items
+ * @returns
+ */
+function shortenIds(items) {
+ if (items && Array.isArray(items)) {
+ return deepClone(
+ items.map(item => {
+ item.short_id = getShortId(item.id)
+ delete item.id
+ return item
+ })
+ )
+ }
+ return items
+}
+
+/**
+ * 清理一组数据的id
+ * @param {*} items
+ * @returns
+ */
+function cleanIds(items) {
+ if (items && Array.isArray(items)) {
+ return deepClone(
+ items.map(item => {
+ delete item.id
+ return item
+ })
+ )
+ }
+ return items
+}
+
/**
* 清理block数据
*/
-function cleanBlock(post) {
+function cleanBlock(item) {
+ const post = deepClone(item)
const pageBlock = post?.blockMap?.block
- for (const i in pageBlock) {
- pageBlock[i] = cleanBlock(pageBlock[i])
- delete pageBlock[i]?.role
- delete pageBlock[i]?.value?.version
- delete pageBlock[i]?.value?.created_by_table
- delete pageBlock[i]?.value?.created_by_id
- delete pageBlock[i]?.value?.last_edited_by_table
- delete pageBlock[i]?.value?.last_edited_by_id
- delete pageBlock[i]?.value?.space_id
- delete pageBlock[i]?.value?.version
- delete pageBlock[i]?.value?.format?.copied_from_pointer
- delete pageBlock[i]?.value?.format?.block_locked_by
- delete pageBlock[i]?.value?.parent_table
- delete pageBlock[i]?.value?.copied_from_pointer
- delete pageBlock[i]?.value?.copied_from
- delete pageBlock[i]?.value?.created_by_table
- delete pageBlock[i]?.value?.created_by_id
- delete pageBlock[i]?.value?.last_edited_by_table
- delete pageBlock[i]?.value?.last_edited_by_id
- delete pageBlock[i]?.value?.permissions
- delete pageBlock[i]?.value?.alive
- }
-
+ // delete post?.id
// delete post?.blockMap?.collection
+
+ if (pageBlock) {
+ for (const i in pageBlock) {
+ pageBlock[i] = cleanBlock(pageBlock[i])
+ delete pageBlock[i]?.role
+ delete pageBlock[i]?.value?.version
+ delete pageBlock[i]?.value?.created_by_table
+ delete pageBlock[i]?.value?.created_by_id
+ delete pageBlock[i]?.value?.last_edited_by_table
+ delete pageBlock[i]?.value?.last_edited_by_id
+ delete pageBlock[i]?.value?.space_id
+ delete pageBlock[i]?.value?.version
+ delete pageBlock[i]?.value?.format?.copied_from_pointer
+ delete pageBlock[i]?.value?.format?.block_locked_by
+ delete pageBlock[i]?.value?.parent_table
+ delete pageBlock[i]?.value?.copied_from_pointer
+ delete pageBlock[i]?.value?.copied_from
+ delete pageBlock[i]?.value?.created_by_table
+ delete pageBlock[i]?.value?.created_by_id
+ delete pageBlock[i]?.value?.last_edited_by_table
+ delete pageBlock[i]?.value?.last_edited_by_id
+ delete pageBlock[i]?.value?.permissions
+ delete pageBlock[i]?.value?.alive
+ }
+ }
return post
}
@@ -290,7 +347,6 @@ export function getNavPages({ allPages }) {
return (
post &&
post?.slug &&
- !post?.slug?.startsWith('http') &&
post?.type === 'Post' &&
post?.status === 'Published'
)
@@ -320,7 +376,7 @@ async function getNotice(post) {
return null
}
- post.blockMap = await getPostBlocks(post.id, 'data-notice')
+ post.blockMap = await getPage(post.id, 'data-notice')
return post
}
@@ -372,7 +428,7 @@ const EmptyData = pageId => {
*/
async function getDataBaseInfoByNotionAPI({ pageId, from }) {
console.log('[Fetching Data]', pageId, from)
- const pageRecordMap = await getPostBlocks(pageId, from)
+ const pageRecordMap = await getPage(pageId, from)
if (!pageRecordMap) {
console.error('can`t get Notion Data ; Which id is: ', pageId)
return {}
@@ -455,6 +511,7 @@ async function getDataBaseInfoByNotionAPI({ pageId, from }) {
adjustPageProperties(element, NOTION_CONFIG)
})
+ // 站点基础信息
const siteInfo = getSiteInfo({ collection, block, pageId })
// 文章计数
@@ -468,7 +525,7 @@ async function getDataBaseInfoByNotionAPI({ pageId, from }) {
return (
post &&
post?.slug &&
- !post?.slug?.startsWith('http') &&
+ // !post?.slug?.startsWith('http') &&
(post?.status === 'Invisible' || post?.status === 'Published')
)
})
@@ -490,11 +547,17 @@ async function getDataBaseInfoByNotionAPI({ pageId, from }) {
)
})?.[0]
)
+ // 所有分类
const categoryOptions = getAllCategories({
allPages,
categoryOptions: getCategoryOptions(schema)
})
- const tagOptions = getAllTags({ allPages, tagOptions: getTagOptions(schema) })
+ // 所有标签
+ const tagOptions = getAllTags({
+ allPages,
+ tagOptions: getTagOptions(schema),
+ NOTION_CONFIG
+ })
// 旧的菜单
const customNav = getCustomNav({
allPages: collectionData.filter(
diff --git a/lib/global.js b/lib/global.js
index d673c3ea..1dcd0c9f 100644
--- a/lib/global.js
+++ b/lib/global.js
@@ -1,5 +1,6 @@
import {
THEMES,
+ getThemeConfig,
initDarkMode,
saveDarkModeToLocalStorage
} from '@/themes/theme'
@@ -29,11 +30,14 @@ export function GlobalContextProvider(props) {
tagOptions,
NOTION_CONFIG
} = props
+
const [lang, updateLang] = useState(NOTION_CONFIG?.LANG || LANG) // 默认语言
const [locale, updateLocale] = useState(
generateLocaleDict(NOTION_CONFIG?.LANG || LANG)
) // 默认语言
const [theme, setTheme] = useState(NOTION_CONFIG?.THEME || THEME) // 默认博客主题
+ const [THEME_CONFIG, SET_THEME_CONFIG] = useState(null) // 主题配置
+
const defaultDarkMode = NOTION_CONFIG?.APPEARANCE || APPEARANCE
const [isDarkMode, updateDarkMode] = useState(defaultDarkMode === 'dark') // 默认深色模式
const [onLoading, setOnLoading] = useState(false) // 抓取文章数据
@@ -54,6 +58,12 @@ export function GlobalContextProvider(props) {
return newTheme
}
+ // 抓取主题配置
+ const updateThemeConfig = async theme => {
+ const config = await getThemeConfig(theme)
+ SET_THEME_CONFIG(config)
+ }
+
// 切换深色模式
const toggleDarkMode = () => {
const newStatus = !isDarkMode
@@ -79,7 +89,10 @@ export function GlobalContextProvider(props) {
useEffect(() => {
initDarkMode(updateDarkMode, defaultDarkMode)
initLocale(lang, locale, updateLang, updateLocale)
- redirectUserLang(NOTION_PAGE_ID)
+ // 可以
+ if (NOTION_CONFIG?.REDIRECT_LANG) {
+ redirectUserLang(NOTION_PAGE_ID)
+ }
}, [])
// 加载进度条
@@ -96,6 +109,9 @@ export function GlobalContextProvider(props) {
setOnLoading(false)
}
+ const currentTheme = router?.query?.theme || theme
+ updateThemeConfig(currentTheme)
+
router.events.on('routeChangeStart', handleStart)
router.events.on('routeChangeError', handleStop)
router.events.on('routeChangeComplete', handleStop)
@@ -111,6 +127,7 @@ export function GlobalContextProvider(props) {
value={{
fullWidth,
NOTION_CONFIG,
+ THEME_CONFIG,
toggleDarkMode,
onLoading,
setOnLoading,
diff --git a/lib/lang/en-US.js b/lib/lang/en-US.js
index 47bb171c..6b40a44c 100644
--- a/lib/lang/en-US.js
+++ b/lib/lang/en-US.js
@@ -14,11 +14,15 @@ export default {
INDEX: 'Home',
RSS: 'RSS',
SEARCH: 'Search',
+ NAVIGATOR: 'NAV',
ABOUT: 'About',
MAIL: 'E-Mail',
ARCHIVE: 'Archive'
},
COMMON: {
+ THEME: 'Theme',
+ ARTICLE_LIST: 'Article List',
+ RECOMMEND_POSTS: 'Recommend Posts',
MORE: 'More',
NO_MORE: 'No More',
LATEST_POSTS: 'Latest posts',
@@ -33,15 +37,21 @@ export default {
COPYRIGHT: 'Copyright',
AUTHOR: 'Author',
URL: 'URL',
+ NOW: 'NOW',
+ RECOMMEND_BADGES: 'Recommend',
+ BLOG: 'Blog',
POSTS: 'Posts',
ARTICLE: 'Article',
VISITORS: 'Visitors',
VIEWS: 'Views',
- COPYRIGHT_NOTICE: 'All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!',
+ PAGE_URL_COPIED: 'Page URL copied',
+ 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',
PASSWORD_ERROR: 'Password Error!',
ARTICLE_LOCK_TIPS: 'Please Enter the password:',
+ ARTICLE_UNLOCK_TIPS: 'Article Unlocked',
NO_RESULTS_FOUND: 'No results found.',
SUBMIT: 'Submit',
POST_TIME: 'Post on',
@@ -55,7 +65,8 @@ export default {
START_READING: 'Start Reading',
MINUTE: 'min',
WORD_COUNT: 'Words',
- READ_TIME: 'Read Time'
+ READ_TIME: 'Read Time',
+ NEXT_POST: '下一篇'
},
PAGINATION: {
PREV: 'Prev',
diff --git a/lib/lang/ja-JP.js b/lib/lang/ja-JP.js
index c27eef0b..628b28b3 100644
--- a/lib/lang/ja-JP.js
+++ b/lib/lang/ja-JP.js
@@ -29,11 +29,14 @@ export default {
ARTICLE: '記事',
VISITORS: '人の訪問者',
VIEWS: '回の閲覧',
- COPYRIGHT_NOTICE: 'この記事はCC BY-NC-SA 4.0 ライセンスの下でライセンスされています。転載する場合には出典を明らかにしてください。',
+ COPYRIGHT_NOTICE:
+ 'この記事はCC BY-NC-SA 4.0 ライセンスの下でライセンスされています。転載する場合には出典を明らかにしてください。',
RESULT_OF_SEARCH: '個の検索結果',
ARTICLE_DETAIL: '記事の詳細',
PASSWORD_ERROR: 'パスワードが違います!',
- ARTICLE_LOCK_TIPS: 'この記事はロックされています。アクセスパスワードを入力してください。',
+ ARTICLE_LOCK_TIPS:
+ 'この記事はロックされています。アクセスパスワードを入力してください。',
+ ARTICLE_UNLOCK_TIPS: '記事がロック解除されました',
SUBMIT: '送信',
POST_TIME: '公開日',
LAST_EDITED_TIME: '最終更新日',
diff --git a/lib/lang/zh-CN.js b/lib/lang/zh-CN.js
index a2c8b1c7..c49ed544 100644
--- a/lib/lang/zh-CN.js
+++ b/lib/lang/zh-CN.js
@@ -20,6 +20,9 @@ export default {
ARCHIVE: '归档'
},
COMMON: {
+ THEME: 'Theme',
+ ARTICLE_LIST: '文章列表',
+ RECOMMEND_POSTS: '推荐文章',
MORE: '更多',
NO_MORE: '没有更多了',
LATEST_POSTS: '最新发布',
@@ -35,16 +38,21 @@ export default {
AUTHOR: '作者',
URL: '链接',
ANALYTICS: '统计',
+ RECOMMEND_BADGES: '荐',
+ BLOG: '博客',
+ NOW: '此刻',
POSTS: '篇文章',
ARTICLE: '文章',
VISITORS: '位访客',
VIEWS: '次查看',
+ PAGE_URL_COPIED: '页面地址已复制',
COPYRIGHT_NOTICE: '本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。',
RESULT_OF_SEARCH: '篇搜索到的结果',
NO_RESULTS_FOUND: '没有找到文章',
ARTICLE_DETAIL: '文章详情',
PASSWORD_ERROR: '密码错误!',
ARTICLE_LOCK_TIPS: '文章已上锁,请输入访问密码',
+ ARTICLE_UNLOCK_TIPS: '文章已解锁',
SUBMIT: '提交',
POST_TIME: '发布于',
LAST_EDITED_TIME: '最后更新',
@@ -57,7 +65,8 @@ export default {
START_READING: '开始阅读',
MINUTE: '分钟',
WORD_COUNT: '字数',
- READ_TIME: '阅读时长'
+ READ_TIME: '阅读时长',
+ NEXT_POST: '下一篇'
},
PAGINATION: {
PREV: '上页',
diff --git a/lib/lang/zh-HK.js b/lib/lang/zh-HK.js
index f434fe6e..6e9df618 100644
--- a/lib/lang/zh-HK.js
+++ b/lib/lang/zh-HK.js
@@ -5,7 +5,39 @@ export default {
RSS: '訂閱',
SEARCH: '搜尋',
ABOUT: '關於',
- MAIL: '電郵'
+ MAIL: '電郵',
+ NAVIGATOR: '導航',
+ ARCHIVE: '封存'
+ },
+ COMMON: {
+ ARTICLE_LIST: '文章列表',
+ MORE: '更多',
+ NO_MORE: '沒有更多了',
+ LATEST_POSTS: '最新文章',
+ TAGS: '標籤',
+ NO_TAG: '無標籤',
+ CATEGORY: '分類',
+ SHARE: '分享',
+ SCAN_QR_CODE: 'QRCode',
+ URL_COPIED: '連結已複製!',
+ TABLE_OF_CONTENTS: '目錄',
+ RELATE_POSTS: '相關文章',
+ COPYRIGHT: '著作權',
+ AUTHOR: '作者',
+ URL: '連結',
+ ANALYTICS: '分析',
+ POSTS: '篇文章',
+ ARTICLE: '文章',
+ VISITORS: '位訪客',
+ VIEWS: '次查看',
+ COPYRIGHT_NOTICE: '本文採用 CC BY-NC-SA 4.0 許可協議,轉載請註明出處。',
+ RESULT_OF_SEARCH: '篇搜尋到的结果',
+ ARTICLE_DETAIL: '完整文章',
+ PASSWORD_ERROR: '密碼錯誤!',
+ ARTICLE_LOCK_TIPS: '文章已上鎖,請輸入訪問密碼',
+ SUBMIT: '提交',
+ POST_TIME: '发布于',
+ LAST_EDITED_TIME: '最后更新'
},
PAGINATION: {
PREV: '上一頁',
@@ -13,7 +45,7 @@ export default {
},
SEARCH: {
ARTICLES: '搜尋文章',
- TAGS: '搜尋標簽'
+ TAGS: '搜尋標籤'
},
POST: {
BACK: '返回',
diff --git a/lib/lang/zh-TW.js b/lib/lang/zh-TW.js
index de746c08..1fe2dbb1 100644
--- a/lib/lang/zh-TW.js
+++ b/lib/lang/zh-TW.js
@@ -10,6 +10,7 @@ export default {
ARCHIVE: '封存'
},
COMMON: {
+ ARTICLE_LIST: '文章列表',
MORE: '更多',
NO_MORE: '沒有更多了',
LATEST_POSTS: '最新文章',
diff --git a/lib/notion/mapPageUrl.js b/lib/notion/convertInnerUrl.js
similarity index 57%
rename from lib/notion/mapPageUrl.js
rename to lib/notion/convertInnerUrl.js
index 80fe70d8..8762d805 100644
--- a/lib/notion/mapPageUrl.js
+++ b/lib/notion/convertInnerUrl.js
@@ -1,33 +1,44 @@
-import { uuidToId } from 'notion-utils'
+import { idToUuid } from 'notion-utils'
import { checkStrIsNotionId, getLastPartOfUrl, isBrowser } from '../utils'
/**
* 处理页面内连接跳转:
- * 1. 若是本站域名,则在当前窗口打开、不开新窗口
- * 2. 若是Notion笔记中的内链,尝试转换成博客中现有的文章地址
+ * 1.若是本站域名,则在当前窗口打开、不开新窗口
+ * 2.url是notion-id,转成站内文章链接
*/
-export const mapPageUrl = allPages => {
+export const convertInnerUrl = allPages => {
if (isBrowser) {
+ const allAnchorTags = document
+ ?.getElementById('notion-article')
+ ?.getElementsByTagName('a')
+
+ if (!allAnchorTags) {
+ return
+ }
const currentURL = window.location.origin + window.location.pathname
- const allAnchorTags = document.getElementsByTagName('a') // 或者使用 document.querySelectorAll('a') 获取 NodeList
+ // url替换成slug
for (const anchorTag of allAnchorTags) {
// 检查url
if (anchorTag?.href) {
// 如果url是一个Notion_id,尝试匹配成博客的文章内链
const slug = getLastPartOfUrl(anchorTag.href)
if (checkStrIsNotionId(slug)) {
- const slugPage = allPages?.find(page => uuidToId(page.id) === slug)
+ const slugPage = allPages?.find(page => {
+ return idToUuid(slug).indexOf(page.short_id) === 0
+ })
if (slugPage) {
anchorTag.href = slugPage?.href
}
}
}
+ }
+ // 链接在当前页面打开
+ for (const anchorTag of allAnchorTags) {
if (anchorTag?.target === '_blank') {
const hrefWithoutQueryHash = anchorTag.href.split('?')[0].split('#')[0]
const hrefWithRelativeHash =
- currentURL.split('#')[0] + anchorTag.href.split('#')[1]
-
+ currentURL.split('#')[0] || '' + anchorTag.href.split('#')[1] || ''
if (
currentURL === hrefWithoutQueryHash ||
currentURL === hrefWithRelativeHash
diff --git a/lib/notion/getAllCategories.js b/lib/notion/getAllCategories.js
index 97c8ab3a..c7e66ba2 100644
--- a/lib/notion/getAllCategories.js
+++ b/lib/notion/getAllCategories.js
@@ -4,7 +4,7 @@ import { isIterable } from '../utils'
* 获取所有文章的标签
* @param allPosts
* @param sliceCount 默认截取数量为12,若为0则返回全部
- * @param tagOptions tags的下拉选项
+ * @param categoryOptions categories的下拉选项
* @returns {Promise<{}|*[]>}
*/
@@ -13,8 +13,14 @@ import { isIterable } from '../utils'
* @param allPosts
* @returns {Promise<{}|*[]>}
*/
-export function getAllCategories({ allPages, categoryOptions, sliceCount = 0 }) {
- const allPosts = allPages?.filter(page => page.type === 'Post' && page.status === 'Published')
+export function getAllCategories({
+ allPages,
+ categoryOptions,
+ sliceCount = 0
+}) {
+ const allPosts = allPages?.filter(
+ page => page.type === 'Post' && page.status === 'Published'
+ )
if (!allPosts || !categoryOptions) {
return []
}
diff --git a/lib/notion/getAllTags.js b/lib/notion/getAllTags.js
index 4c7559b9..cac8dac7 100644
--- a/lib/notion/getAllTags.js
+++ b/lib/notion/getAllTags.js
@@ -1,5 +1,5 @@
+import { siteConfig } from '../config'
import { isIterable } from '../utils'
-import BLOG from '@/blog.config'
/**
* 获取所有文章的标签
@@ -8,8 +8,15 @@ import BLOG from '@/blog.config'
* @param tagOptions tags的下拉选项
* @returns {Promise<{}|*[]>}
*/
-export function getAllTags({ allPages, sliceCount = 0, tagOptions }) {
- const allPosts = allPages?.filter(page => page.type === 'Post' && page.status === 'Published')
+export function getAllTags({
+ allPages,
+ sliceCount = 0,
+ tagOptions,
+ NOTION_CONFIG
+}) {
+ const allPosts = allPages?.filter(
+ page => page.type === 'Post' && page.status === 'Published'
+ )
if (!allPosts || !tagOptions) {
return []
@@ -27,7 +34,12 @@ export function getAllTags({ allPages, sliceCount = 0, tagOptions }) {
})
const list = []
- const { IS_TAG_COLOR_DISTINGUISHED } = BLOG
+ const IS_TAG_COLOR_DISTINGUISHED = siteConfig(
+ 'IS_TAG_COLOR_DISTINGUISHED',
+ false,
+ NOTION_CONFIG
+ )
+ const TAG_SORT_BY_COUNT = siteConfig('TAG_SORT_BY_COUNT', true, NOTION_CONFIG)
if (isIterable(tagOptions)) {
if (!IS_TAG_COLOR_DISTINGUISHED) {
// 如果不区分颜色, 那么不同颜色相同名称的tag当做同一种tag
@@ -52,7 +64,10 @@ export function getAllTags({ allPages, sliceCount = 0, tagOptions }) {
}
// 按照数量排序
- // list.sort((a, b) => b.count - a.count)
+ if (TAG_SORT_BY_COUNT) {
+ list.sort((a, b) => b.count - a.count)
+ }
+
if (sliceCount && sliceCount > 0) {
return list.slice(0, sliceCount)
} else {
diff --git a/lib/notion/getNotionConfig.js b/lib/notion/getNotionConfig.js
index 889005f2..c0ef7c29 100644
--- a/lib/notion/getNotionConfig.js
+++ b/lib/notion/getNotionConfig.js
@@ -9,7 +9,7 @@
import { getDateValue, getTextContent } from 'notion-utils'
import { deepClone } from '../utils'
import getAllPageIds from './getAllPageIds'
-import { getPostBlocks } from './getPostBlocks'
+import { getPage } from './getPostBlocks'
/**
* 从Notion中读取Config配置表
@@ -41,12 +41,12 @@ export async function getConfigMapFromConfigPage(allPages) {
}
const configPageId = configPage.id
// console.log('[Notion配置]请求配置数据 ', configPage.id)
- let pageRecordMap = await getPostBlocks(configPageId, 'config-table')
+ let pageRecordMap = await getPage(configPageId, 'config-table')
// console.log('配置中心Page', configPageId, pageRecordMap)
let content = pageRecordMap.block[configPageId].value.content
for (const table of ['Config-Table', 'CONFIG-TABLE']) {
if (content) break
- pageRecordMap = await getPostBlocks(configPageId, table)
+ pageRecordMap = await getPage(configPageId, table)
content = pageRecordMap.block[configPageId].value.content
}
diff --git a/lib/notion/getNotionPost.js b/lib/notion/getNotionPost.js
index 3e096a11..f5aabb2a 100644
--- a/lib/notion/getNotionPost.js
+++ b/lib/notion/getNotionPost.js
@@ -2,7 +2,7 @@ import BLOG from '@/blog.config'
import { idToUuid } from 'notion-utils'
import { defaultMapImageUrl } from 'react-notion-x'
import formatDate from '../utils/formatDate'
-import { getPostBlocks } from './getPostBlocks'
+import { getPage } from './getPostBlocks'
/**
* 根据页面ID获取内容
@@ -10,7 +10,7 @@ import { getPostBlocks } from './getPostBlocks'
* @returns
*/
export async function getPost(pageId) {
- const blockMap = await getPostBlocks(pageId, 'slug')
+ const blockMap = await getPage(pageId, 'slug')
if (!blockMap) {
return null
}
diff --git a/lib/notion/getPageProperties.js b/lib/notion/getPageProperties.js
index 38eede18..53d7ce87 100644
--- a/lib/notion/getPageProperties.js
+++ b/lib/notion/getPageProperties.js
@@ -6,10 +6,11 @@ import formatDate from '../utils/formatDate'
import md5 from 'js-md5'
import { siteConfig } from '../config'
import {
- checkContainHttp,
- convertUrlStartWithOneSlash,
- sliceUrlFromHttp
+ checkStartWithHttp,
+ convertUrlStartWithOneSlash,
+ getLastSegmentFromUrl
} from '../utils'
+import { extractLangPrefix } from '../utils/pageId'
import { mapImgUrl } from './mapImage'
/**
@@ -94,6 +95,7 @@ export default async function getPageProperties(
properties.type = properties.type?.[0] || ''
properties.status = properties.status?.[0] || ''
properties.category = properties.category?.[0] || ''
+ properties.comment = properties.comment?.[0] || ''
// 映射值:用户个性化type和status字段的下拉框选项,在此映射回代码的英文标识
mapProperties(properties)
@@ -185,26 +187,38 @@ export function adjustPageProperties(properties, NOTION_CONFIG) {
properties.name = properties.title ?? ''
}
- // 开启伪静态路径
- if (JSON.parse(NOTION_CONFIG?.PSEUDO_STATIC || BLOG.PSEUDO_STATIC)) {
- if (
- !properties?.href?.endsWith('.html') &&
- !properties?.href?.startsWith('http')
- ) {
- properties.href += '.html'
- }
- }
-
- // 检查处理外链
- properties.href = checkContainHttp(properties?.href)
- ? sliceUrlFromHttp(properties?.href)
- : convertUrlStartWithOneSlash(properties?.href)
-
- // 设置链接在页内或新页面打开
- if (properties.href?.indexOf('http') === 0) {
+ // http or https 开头的视为外链
+ if (checkStartWithHttp(properties?.href)) {
+ properties.href = properties?.slug
properties.target = '_blank'
} else {
properties.target = '_self'
+ // 伪静态路径右侧拼接.html
+ if (siteConfig('PSEUDO_STATIC', false, NOTION_CONFIG)) {
+ if (
+ !properties?.href?.endsWith('.html') &&
+ properties?.href !== '' &&
+ properties?.href !== '#' &&
+ properties?.href !== '/'
+ ) {
+ properties.href += '.html'
+ }
+ }
+
+ // 相对路径转绝对路径:url左侧拼接 /
+ properties.href = convertUrlStartWithOneSlash(properties?.href)
+ }
+
+ // 如果跳转链接是多语言,则在新窗口打开
+ if (BLOG.NOTION_PAGE_ID.indexOf(',') > 0) {
+ const siteIds = BLOG.NOTION_PAGE_ID.split(',')
+ for (let index = 0; index < siteIds.length; index++) {
+ const siteId = siteIds[index]
+ const prefix = extractLangPrefix(siteId)
+ if (getLastSegmentFromUrl(properties.href) === prefix) {
+ properties.target = '_blank'
+ }
+ }
}
// 密码字段md5
@@ -221,6 +235,10 @@ export function adjustPageProperties(properties, NOTION_CONFIG) {
* @returns
*/
function generateCustomizeSlug(postProperties, NOTION_CONFIG) {
+ // 外链不处理
+ if (checkStartWithHttp(postProperties.slug)) {
+ return postProperties.slug
+ }
let fullPrefix = ''
const allSlugPatterns = siteConfig(
'POST_URL_PREFIX',
@@ -272,5 +290,10 @@ function generateCustomizeSlug(postProperties, NOTION_CONFIG) {
if (fullPrefix.endsWith('/')) {
fullPrefix = fullPrefix.substring(0, fullPrefix.length - 1) // 去掉尾部部的"/"
}
- return `${fullPrefix}/${postProperties.slug ?? postProperties.id}`
+
+ if(fullPrefix){
+ return `${fullPrefix}/${postProperties.slug ?? postProperties.id}`
+ }else{
+ return `${postProperties.slug ?? postProperties.id}`
+ }
}
diff --git a/lib/notion/getPostBlocks.js b/lib/notion/getPostBlocks.js
index 0b151f17..2859345f 100644
--- a/lib/notion/getPostBlocks.js
+++ b/lib/notion/getPostBlocks.js
@@ -10,7 +10,7 @@ import { deepClone, delay } from '../utils'
* @param {*} slice
* @returns
*/
-export async function getPostBlocks(id, from, slice) {
+export async function getPage(id, from, slice) {
const cacheKey = 'page_block_' + id
let pageBlock = await getDataFromCache(cacheKey)
if (pageBlock) {
@@ -27,28 +27,6 @@ export async function getPostBlocks(id, from, slice) {
return pageBlock
}
-/**
- * 针对在getDataBaseInfoByNotionAPI=>getPostBlocks中获取不到的溢出的block-id,用此方法另外抓取
- * @param {*} id
- * @param {*} from
- * @returns
- */
-export async function getSingleBlock(id, from) {
- const cacheKey = 'single_block_' + id
- let pageBlock = await getDataFromCache(cacheKey)
- if (pageBlock) {
- // console.log('[API<<--缓存]', `from:${from}`, cacheKey)
- return pageBlock
- }
-
- pageBlock = await getPageWithRetry(id, 'single_' + from)
-
- if (pageBlock) {
- await setDataToCache(cacheKey, pageBlock)
- }
- return pageBlock
-}
-
/**
* 调用接口,失败会重试
* @param {*} id
@@ -103,49 +81,69 @@ export async function getPageWithRetry(id, from, retryAttempts = 3) {
function filterPostBlocks(id, blockMap, slice) {
const clonePageBlock = deepClone(blockMap)
let count = 0
+ const blocksToProcess = Object.keys(clonePageBlock?.block || {})
// 循环遍历文档的每个block
- for (const i in clonePageBlock?.block) {
- const b = clonePageBlock?.block[i]
- if (slice && slice > 0 && count > slice) {
- delete clonePageBlock?.block[i]
- continue
+ for (let i = 0; i < blocksToProcess.length; i++) {
+ const blockId = blocksToProcess[i]
+ const b = clonePageBlock?.block[blockId]
+
+ if (slice && slice > 0 && count > slice) {
+ delete clonePageBlock?.block[blockId]
+ continue
+ }
+
+ // 当BlockId等于PageId时移除
+ if (b?.value?.id === id) {
+ // 此block含有敏感信息
+ delete b?.value?.properties
+ continue
+ }
+
+ count++
+
+ if (b?.value?.type === 'sync_block' && b?.value?.children) {
+ const childBlocks = b.value.children
+ // 移除同步块
+ delete clonePageBlock.block[blockId]
+ // 用子块替代同步块
+ childBlocks.forEach((childBlock, index) => {
+ const newBlockId = `${blockId}_child_${index}`
+ clonePageBlock.block[newBlockId] = childBlock
+ blocksToProcess.splice(i + index + 1, 0, newBlockId)
+ })
+ // 重新处理新加入的子块
+ i--
+ continue
+ }
+
+ // 处理 c++、c#、汇编等语言名字映射
+ if (b?.value?.type === 'code') {
+ if (b?.value?.properties?.language?.[0][0] === 'C++') {
+ b.value.properties.language[0][0] = 'cpp'
}
- // 当BlockId等于PageId时移除
- if (b?.value?.id === id) {
- // 此block含有敏感信息
- delete b?.value?.properties
- continue
+ if (b?.value?.properties?.language?.[0][0] === 'C#') {
+ b.value.properties.language[0][0] = 'csharp'
}
-
- count++
- // 处理 c++、c#、汇编等语言名字映射
- if (b?.value?.type === 'code') {
- if (b?.value?.properties?.language?.[0][0] === 'C++') {
- b.value.properties.language[0][0] = 'cpp'
- }
- if (b?.value?.properties?.language?.[0][0] === 'C#') {
- b.value.properties.language[0][0] = 'csharp'
- }
- if (b?.value?.properties?.language?.[0][0] === 'Assembly') {
- b.value.properties.language[0][0] = 'asm6502'
- }
- }
-
- // 如果是文件,或嵌入式PDF,需要重新加密签名
- if (
- (b?.value?.type === 'file' ||
- b?.value?.type === 'pdf' ||
- b?.value?.type === 'video' ||
- b?.value?.type === 'audio') &&
- b?.value?.properties?.source?.[0][0] &&
- b?.value?.properties?.source?.[0][0].indexOf('amazonaws.com') > 0
- ) {
- const oldUrl = b?.value?.properties?.source?.[0][0]
- const newUrl = `https://notion.so/signed/${encodeURIComponent(oldUrl)}?table=block&id=${b?.value?.id}`
- b.value.properties.source[0][0] = newUrl
+ if (b?.value?.properties?.language?.[0][0] === 'Assembly') {
+ b.value.properties.language[0][0] = 'asm6502'
}
}
+
+ // 如果是文件,或嵌入式PDF,需要重新加密签名
+ if (
+ (b?.value?.type === 'file' ||
+ b?.value?.type === 'pdf' ||
+ b?.value?.type === 'video' ||
+ b?.value?.type === 'audio') &&
+ b?.value?.properties?.source?.[0][0] &&
+ b?.value?.properties?.source?.[0][0].indexOf('amazonaws.com') > 0
+ ) {
+ const oldUrl = b?.value?.properties?.source?.[0][0]
+ const newUrl = `https://notion.so/signed/${encodeURIComponent(oldUrl)}?table=block&id=${b?.value?.id}`
+ b.value.properties.source[0][0] = newUrl
+ }
+}
// 去掉不用的字段
if (id === BLOG.NOTION_PAGE_ID) {
@@ -162,6 +160,11 @@ function filterPostBlocks(id, blockMap, slice) {
* @returns
*/
export const fetchInBatches = async (ids, batchSize = 100) => {
+ // 如果 ids 不是数组,则将其转换为数组
+ if (!Array.isArray(ids)) {
+ ids = [ids]
+ }
+
const authToken = BLOG.NOTION_ACCESS_TOKEN || null
const api = new NotionAPI({
authToken,
@@ -171,7 +174,7 @@ export const fetchInBatches = async (ids, batchSize = 100) => {
let fetchedBlocks = {}
for (let i = 0; i < ids.length; i += batchSize) {
const batch = ids.slice(i, i + batchSize)
- console.log('[API-->>请求] Fetching missing blocks', ids.length)
+ console.log('[API-->>请求] Fetching missing blocks', batch, ids.length)
const start = new Date().getTime()
const pageChunk = await api.getBlocks(batch)
const end = new Date().getTime()
diff --git a/lib/notion/mapImage.js b/lib/notion/mapImage.js
index 491632bc..5bb1e9b1 100644
--- a/lib/notion/mapImage.js
+++ b/lib/notion/mapImage.js
@@ -110,6 +110,8 @@ const compressImage = (image, width, quality = 50, fmt = 'webp') => {
return image
}
+ if (image.includes(".svg")) return image
+
if (!width || width === 0) {
width = siteConfig('IMAGE_COMPRESS_WIDTH')
}
diff --git a/lib/password.js b/lib/password.js
new file mode 100644
index 00000000..67b341a6
--- /dev/null
+++ b/lib/password.js
@@ -0,0 +1,37 @@
+import { isBrowser } from './utils'
+
+/**
+ * 获取默认密码
+ * 用户可以通过url中拼接参数,输入密码
+ * 输入过一次的密码会被存储在浏览器中,便于下一次免密访问
+ * 返回的是一组历史密码,便于客户端多次尝试
+ */
+export const getPasswordQuery = path => {
+ // 使用 URL 对象解析 URL
+ const url = new URL(path, isBrowser ? window.location.origin : '')
+
+ // 获取查询参数
+ const queryParams = Object.fromEntries(url.searchParams.entries())
+
+ // 请求中带着密码
+ if (queryParams.password) {
+ // 将已输入密码作为默认密码存放在 localStorage,便于下次读取并自动尝试
+ localStorage.setItem('password_default', queryParams.password)
+ }
+
+ // 获取路径部分
+ const cleanedPath = url.pathname
+
+ // 从 localStorage 中获取相关密码
+ const storedPassword = localStorage.getItem('password_' + cleanedPath)
+ const defaultPassword = localStorage.getItem('password_default')
+
+ // 将所有密码存储在一个数组中,并过滤掉无效值
+ const passwords = [
+ queryParams.password,
+ storedPassword,
+ defaultPassword
+ ].filter(Boolean)
+
+ return passwords
+}
diff --git a/lib/plugins/algolia.js b/lib/plugins/algolia.js
index fe2f9a83..d161bf58 100644
--- a/lib/plugins/algolia.js
+++ b/lib/plugins/algolia.js
@@ -6,7 +6,7 @@ import algoliasearch from 'algoliasearch'
* 生成全文索引
* @param {*} allPages
*/
-const generateAlgoliaSearch = async({ allPages, force = false }) => {
+const generateAlgoliaSearch = async ({ allPages, force = false }) => {
allPages?.forEach(p => {
// 判断这篇文章是否需要重新创建索引
if (p && !p.password) {
@@ -19,7 +19,7 @@ const generateAlgoliaSearch = async({ allPages, force = false }) => {
* 上传数据
* 根据上次修改文章日期和上次更新索引数据判断是否需要更新algolia索引
*/
-const uploadDataToAlgolia = async(post) => {
+const uploadDataToAlgolia = async post => {
// Connect and authenticate with your Algolia app
const client = algoliasearch(BLOG.ALGOLIA_APP_ID, BLOG.ALGOLIA_ADMIN_APP_KEY)
@@ -61,14 +61,18 @@ const uploadDataToAlgolia = async(post) => {
summary: post.summary,
lastEditedDate: post.lastEditedDate, // 更新文章时间
lastIndexDate: new Date(), // 更新索引时间
- content: truncate(getPageContentText(post, post.blockMap), 9000) // 索引9000个字节,因为api限制总请求内容上限1万个字节
+ content: truncate(getPageContentText(post, post.blockMap), 8192) // 索引8192个字符,API限制总请求内容上限1万个字节
}
// console.log('更新Algolia索引', record)
- index.saveObject(record).wait().then(r => {
- console.log('Algolia索引更新', r)
- }).catch(err => {
- console.log('Algolia异常', err)
- })
+ index
+ .saveObject(record)
+ .wait()
+ .then(r => {
+ console.log('Algolia索引更新', r)
+ })
+ .catch(err => {
+ console.log('Algolia异常', err)
+ })
}
}
diff --git a/lib/utils/index.js b/lib/utils/index.js
index b8d78f30..27a6494f 100644
--- a/lib/utils/index.js
+++ b/lib/utils/index.js
@@ -47,7 +47,12 @@ export const memorize = Component => {
return memo(MemoizedComponent)
}
-// 转换外链
+/**
+ * 诸如 article/https://test.com 等被错误拼接前缀的slug进行处理
+ * 转换为 https://test.com
+ * @param {*} str
+ * @returns
+ */
export function sliceUrlFromHttp(str) {
// 检查字符串是否包含http
if (str?.includes('http:') || str?.includes('https:')) {
@@ -81,12 +86,25 @@ export function convertUrlStartWithOneSlash(str) {
return str
}
+/**
+ * 是否是一个相对或绝对路径的ur类
+ * @param {*} str
+ * @returns
+ */
+export function isUrl(str) {
+ if (!str) {
+ return false
+ }
+
+ return str?.indexOf('/') === 0 || checkStartWithHttp(str)
+}
+
// 检查是否外链
-export function checkContainHttp(str) {
+export function checkStartWithHttp(str) {
// 检查字符串是否包含http
- if (str?.includes('http:') || str?.includes('https:')) {
+ if (str?.indexOf('http:') === 0 || str?.indexOf('https:') === 0) {
// 如果包含,找到http的位置
- return str?.indexOf('http') > -1
+ return true
} else {
// 不包含
return false
@@ -354,3 +372,19 @@ export const scanAndConvertToLinks = node => {
}
}
}
+
+/**
+ * 获取url最后一个斜杆后面的内容
+ * @param {*} url
+ * @returns
+ */
+export function getLastSegmentFromUrl(url) {
+ if (!url) {
+ return ''
+ }
+ // 去掉 URL 中的查询参数部分
+ const trimmedUrl = url.split('?')[0]
+ // 获取最后一个斜杠后面的内容
+ const segments = trimmedUrl.split('/')
+ return segments[segments.length - 1]
+}
diff --git a/lib/utils/pageId.js b/lib/utils/pageId.js
index e3c648e1..c963df28 100644
--- a/lib/utils/pageId.js
+++ b/lib/utils/pageId.js
@@ -30,4 +30,18 @@ function extractLangId(str) {
}
}
-module.exports = { extractLangPrefix, extractLangId }
+/**
+ * 列表中用过来区分page只需要端的id足够
+ */
+
+function getShortId(uuid) {
+ if (!uuid || uuid.indexOf('-') < 0) {
+ return uuid
+ }
+ // 找到第一个 '-' 的位置
+ const index = uuid.indexOf('-')
+ // 截取从开始到第一个 '-' 之前的部分
+ return uuid.substring(0, index)
+}
+
+module.exports = { extractLangPrefix, extractLangId, getShortId }
diff --git a/lib/utils/post.js b/lib/utils/post.js
index 87852eda..e6402a02 100644
--- a/lib/utils/post.js
+++ b/lib/utils/post.js
@@ -1,7 +1,7 @@
/**
* 文章相关工具
*/
-import { checkContainHttp } from '.'
+import { checkStartWithHttp } from '.'
/**
* 获取文章的关联推荐文章列表,目前根据标签关联性筛选
@@ -50,7 +50,7 @@ export function checkSlugHasNoSlash(row) {
}
return (
(slug.match(/\//g) || []).length === 0 &&
- !checkContainHttp(slug) &&
+ !checkStartWithHttp(slug) &&
row.type.indexOf('Menu') < 0
)
}
@@ -67,7 +67,7 @@ export function checkSlugHasOneSlash(row) {
}
return (
(slug.match(/\//g) || []).length === 1 &&
- !checkContainHttp(slug) &&
+ !checkStartWithHttp(slug) &&
row.type.indexOf('Menu') < 0
)
}
@@ -85,6 +85,6 @@ export function checkSlugHasMorThanTwoSlash(row) {
return (
(slug.match(/\//g) || []).length >= 2 &&
row.type.indexOf('Menu') < 0 &&
- !checkContainHttp(slug)
+ !checkStartWithHttp(slug)
)
}
diff --git a/next.config.js b/next.config.js
index 20a1c311..5e5937cd 100644
--- a/next.config.js
+++ b/next.config.js
@@ -32,6 +32,16 @@ const locales = (function () {
return langs
})()
+// 编译前执行
+// const preBuild = (function () {
+// // 删除 public/sitemap.xml 文件 ; 否则会和/pages/sitemap.xml.js 冲突。
+// const sitemapPath = path.resolve(__dirname, 'public', 'sitemap.xml')
+// if (fs.existsSync(sitemapPath)) {
+// fs.unlinkSync(sitemapPath)
+// console.log('Deleted existing sitemap.xml from public directory')
+// }
+// })()
+
/**
* 扫描指定目录下的文件夹名,用于获取所有主题
* @param {*} directory
@@ -53,7 +63,20 @@ function scanSubdirectories(directory) {
return subdirectories
}
+/**
+ * @type {import('next').NextConfig}
+ */
+
const nextConfig = {
+ output: process.env.EXPORT ? 'export' : undefined,
+ // 多语言, 在export时禁用
+ i18n: process.env.EXPORT
+ ? undefined
+ : {
+ defaultLocale: BLOG.LANG.slice(0, 2),
+ // 支持的所有多语言,按需填写即可
+ locales
+ },
images: {
// 图片压缩
formats: ['image/avif', 'image/webp'],
@@ -71,90 +94,87 @@ const nextConfig = {
},
// 默认将feed重定向至 /public/rss/feed.xml
- async redirects() {
- return [
- {
- source: '/feed',
- destination: '/rss/feed.xml',
- permanent: true
- }
- ]
- },
- // 多语言, 在export时禁用
- i18n:
- process.env.npm_lifecycle_event === 'export'
- ? undefined
- : {
- defaultLocale: BLOG.LANG.slice(0, 2),
- // 支持的所有多语言,按需填写即可
- locales
- },
- // 重写url
- async rewrites() {
- // 处理多语言重定向
- const langsRewrites = []
- if (BLOG.NOTION_PAGE_ID.indexOf(',') > 0) {
- const siteIds = BLOG.NOTION_PAGE_ID.split(',')
- const langs = []
- for (let index = 0; index < siteIds.length; index++) {
- const siteId = siteIds[index]
- const prefix = extractLangPrefix(siteId)
- // 如果包含前缀 例如 zh , en 等
- if (prefix) {
- langs.push(prefix)
- }
- console.log('[Locales]', siteId)
- }
-
- // 映射多语言
- // 示例: source: '/:locale(zh|en)/:path*' ; :locale() 会将语言放入重写后的 `?locale=` 中。
- langsRewrites.push(
- {
- source: `/:locale(${langs.join('|')})/:path*`,
- destination: '/:path*'
- },
- // 匹配没有路径的情况,例如 [domain]/zh 或 [domain]/en
- {
- source: `/:locale(${langs.join('|')})`,
- destination: '/'
- },
- // 匹配没有路径的情况,例如 [domain]/zh/ 或 [domain]/en/
- {
- source: `/:locale(${langs.join('|')})/`,
- destination: '/'
- }
- )
- }
-
- return [
- ...langsRewrites,
- // 伪静态重写
- {
- source: '/:path*.html',
- destination: '/:path*'
- }
- ]
- },
- async headers() {
- return [
- {
- source: '/:path*{/}?',
- headers: [
- { key: 'Access-Control-Allow-Credentials', value: 'true' },
- { key: 'Access-Control-Allow-Origin', value: '*' },
+ redirects: process.env.EXPORT
+ ? undefined
+ : async () => {
+ return [
{
- key: 'Access-Control-Allow-Methods',
- value: 'GET,OPTIONS,PATCH,DELETE,POST,PUT'
- },
- {
- key: 'Access-Control-Allow-Headers',
- value:
- 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'
+ source: '/feed',
+ destination: '/rss/feed.xml',
+ permanent: true
}
]
- }
- ]
- },
+ },
+ // 重写url
+ rewrites: process.env.EXPORT
+ ? undefined
+ : async () => {
+ // 处理多语言重定向
+ const langsRewrites = []
+ if (BLOG.NOTION_PAGE_ID.indexOf(',') > 0) {
+ const siteIds = BLOG.NOTION_PAGE_ID.split(',')
+ const langs = []
+ for (let index = 0; index < siteIds.length; index++) {
+ const siteId = siteIds[index]
+ const prefix = extractLangPrefix(siteId)
+ // 如果包含前缀 例如 zh , en 等
+ if (prefix) {
+ langs.push(prefix)
+ }
+ console.log('[Locales]', siteId)
+ }
+
+ // 映射多语言
+ // 示例: source: '/:locale(zh|en)/:path*' ; :locale() 会将语言放入重写后的 `?locale=` 中。
+ langsRewrites.push(
+ {
+ source: `/:locale(${langs.join('|')})/:path*`,
+ destination: '/:path*'
+ },
+ // 匹配没有路径的情况,例如 [domain]/zh 或 [domain]/en
+ {
+ source: `/:locale(${langs.join('|')})`,
+ destination: '/'
+ },
+ // 匹配没有路径的情况,例如 [domain]/zh/ 或 [domain]/en/
+ {
+ source: `/:locale(${langs.join('|')})/`,
+ destination: '/'
+ }
+ )
+ }
+
+ return [
+ ...langsRewrites,
+ // 伪静态重写
+ {
+ source: '/:path*.html',
+ destination: '/:path*'
+ }
+ ]
+ },
+ headers: process.env.EXPORT
+ ? undefined
+ : async () => {
+ return [
+ {
+ source: '/:path*{/}?',
+ headers: [
+ { key: 'Access-Control-Allow-Credentials', value: 'true' },
+ { key: 'Access-Control-Allow-Origin', value: '*' },
+ {
+ key: 'Access-Control-Allow-Methods',
+ value: 'GET,OPTIONS,PATCH,DELETE,POST,PUT'
+ },
+ {
+ key: 'Access-Control-Allow-Headers',
+ value:
+ 'X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version'
+ }
+ ]
+ }
+ ]
+ },
webpack: (config, { dev, isServer }) => {
// 动态主题:添加 resolve.alias 配置,将动态路径映射到实际路径
if (!isServer) {
diff --git a/package.json b/package.json
index 5e7761c7..55c67a2b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "notion-next",
- "version": "4.5.3",
+ "version": "4.6.1",
"homepage": "https://github.com/tangly1024/NotionNext.git",
"license": "MIT",
"repository": {
@@ -17,8 +17,9 @@
"build": "next build",
"start": "next start",
"post-build": "next-sitemap --config next-sitemap.config.js",
- "export": "next build && next-sitemap --config next-sitemap.config.js && next export",
- "bundle-report": "cross-env ANALYZE=true yarn build"
+ "export": "cross-env EXPORT=true next build && next-sitemap --config next-sitemap.config.js",
+ "bundle-report": "cross-env ANALYZE=true next build",
+ "build-all-in-dev": "cross-env VERCEL_ENV=production next build"
},
"dependencies": {
"@headlessui/react": "^1.7.15",
@@ -29,7 +30,7 @@
"js-md5": "^0.7.3",
"lodash.throttle": "^4.1.1",
"memory-cache": "^0.2.0",
- "next": "13.3.1",
+ "next": "14.2.4",
"notion-client": "6.15.6",
"notion-utils": "6.15.6",
"react": "^18.2.0",
diff --git a/pages/[prefix]/[slug]/[...suffix].js b/pages/[prefix]/[slug]/[...suffix].js
index 2050e81d..d9567c4c 100644
--- a/pages/[prefix]/[slug]/[...suffix].js
+++ b/pages/[prefix]/[slug]/[...suffix].js
@@ -30,17 +30,17 @@ export async function getStaticPaths() {
const from = 'slug-paths'
const { allPages } = await getGlobalData({ from })
-
+ const paths = allPages
+ ?.filter(row => checkSlugHasMorThanTwoSlash(row))
+ .map(row => ({
+ params: {
+ prefix: row.slug.split('/')[0],
+ slug: row.slug.split('/')[1],
+ suffix: row.slug.split('/').slice(2)
+ }
+ }))
return {
- paths: allPages
- ?.filter(row => checkSlugHasMorThanTwoSlash(row))
- .map(row => ({
- params: {
- prefix: row.slug.split('/')[0],
- slug: row.slug.split('/')[1],
- suffix: row.slug.split('/').slice(1)
- }
- })),
+ paths: paths,
fallback: true
}
}
@@ -83,16 +83,18 @@ export async function getStaticProps({
props.post = null
return {
props,
- revalidate: siteConfig(
- 'REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
// 文章内容加载
- if (!props?.posts?.blockMap) {
+ if (!props?.post?.blockMap) {
props.post.blockMap = await getPostBlocks(props.post.id, from)
}
// 生成全文索引 && JSON.parse(BLOG.ALGOLIA_RECREATE_DATA)
@@ -122,11 +124,13 @@ export async function getStaticProps({
delete props.allPages
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/pages/[prefix]/[slug]/index.js b/pages/[prefix]/[slug]/index.js
index 2c844eba..6b50c206 100644
--- a/pages/[prefix]/[slug]/index.js
+++ b/pages/[prefix]/[slug]/index.js
@@ -72,16 +72,18 @@ export async function getStaticProps({ params: { prefix, slug }, locale }) {
props.post = null
return {
props,
- revalidate: siteConfig(
- 'REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
// 文章内容加载
- if (!props?.posts?.blockMap) {
+ if (!props?.post?.blockMap) {
props.post.blockMap = await getPostBlocks(props.post.id, from)
}
// 生成全文索引 && JSON.parse(BLOG.ALGOLIA_RECREATE_DATA)
@@ -111,11 +113,13 @@ export async function getStaticProps({ params: { prefix, slug }, locale }) {
delete props.allPages
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/pages/[prefix]/index.js b/pages/[prefix]/index.js
index 469ca617..dc480fcc 100644
--- a/pages/[prefix]/index.js
+++ b/pages/[prefix]/index.js
@@ -1,7 +1,10 @@
import BLOG from '@/blog.config'
+import useNotification from '@/components/Notification'
import { siteConfig } from '@/lib/config'
import { getGlobalData, getPost, getPostBlocks } from '@/lib/db/getSiteData'
+import { useGlobal } from '@/lib/global'
import { getPageTableOfContents } from '@/lib/notion/getPageTableOfContents'
+import { getPasswordQuery } from '@/lib/password'
import { uploadDataToAlgolia } from '@/lib/plugins/algolia'
import { checkSlugHasNoSlash, getRecommendPost } from '@/lib/utils/post'
import { getLayoutByTheme } from '@/themes/theme'
@@ -19,9 +22,11 @@ import { useEffect, useState } from 'react'
const Slug = props => {
const { post } = props
const router = useRouter()
+ const { locale } = useGlobal()
// 文章锁🔐
const [lock, setLock] = useState(post?.password && post?.password !== '')
+ const { showNotification, Notification } = useNotification()
/**
* 验证文章密码
@@ -36,6 +41,7 @@ const Slug = props => {
setLock(false)
// 输入密码存入localStorage,下次自动提交
localStorage.setItem('password_' + router.asPath, passInput)
+ showNotification(locale.COMMON.ARTICLE_UNLOCK_TIPS) // 设置解锁成功提示显示
return true
}
return false
@@ -56,10 +62,14 @@ const Slug = props => {
}
}
- // 从localStorage中读取上次记录 自动提交密码
- const passInput = localStorage.getItem('password_' + router.asPath)
- if (passInput) {
- validPassword(passInput)
+ // 读取上次记录 自动提交密码
+ const passInputs = getPasswordQuery(router.asPath)
+ if (passInputs.length > 0) {
+ for (const passInput of passInputs) {
+ if (validPassword(passInput)) {
+ break // 密码验证成功,停止尝试
+ }
+ }
}
}, [post])
@@ -83,7 +93,12 @@ const Slug = props => {
theme: siteConfig('THEME'),
router: useRouter()
})
- return
+ return (
+ <>
+
+ {post?.password && post?.password !== '' && !lock &&
}
+ >
+ )
}
export async function getStaticPaths() {
@@ -109,17 +124,17 @@ export async function getStaticProps({ params: { prefix }, locale }) {
let fullSlug = prefix
const from = `slug-props-${fullSlug}`
const props = await getGlobalData({ from, locale })
- if (siteConfig('PSEUDO_STATIC', BLOG.PSEUDO_STATIC, props.NOTION_CONFIG)) {
+ if (siteConfig('PSEUDO_STATIC', false, props.NOTION_CONFIG)) {
if (!fullSlug.endsWith('.html')) {
fullSlug += '.html'
}
}
-
+
// 在列表内查找文章
props.post = props?.allPages?.find(p => {
return (
p.type.indexOf('Menu') < 0 &&
- (p.slug === fullSlug || p.id === idToUuid(fullSlug))
+ (p.slug === prefix || p.id === idToUuid(prefix))
)
})
@@ -136,16 +151,18 @@ export async function getStaticProps({ params: { prefix }, locale }) {
props.post = null
return {
props,
- revalidate: siteConfig(
- 'REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
// 文章内容加载
- if (!props?.posts?.blockMap) {
+ if (!props?.post?.blockMap) {
props.post.blockMap = await getPostBlocks(props.post.id, from)
}
@@ -176,11 +193,13 @@ export async function getStaticProps({ params: { prefix }, locale }) {
delete props.allPages
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/pages/archive/index.js b/pages/archive/index.js
index 9f0803c8..beecf79c 100644
--- a/pages/archive/index.js
+++ b/pages/archive/index.js
@@ -61,11 +61,13 @@ export async function getStaticProps({ locale }) {
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/pages/category/[category]/index.js b/pages/category/[category]/index.js
index 879dc642..ea70b454 100644
--- a/pages/category/[category]/index.js
+++ b/pages/category/[category]/index.js
@@ -49,11 +49,13 @@ export async function getStaticProps({ params: { category }, locale }) {
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/pages/category/[category]/page/[page].js b/pages/category/[category]/page/[page].js
index 39ce44df..120d762a 100644
--- a/pages/category/[category]/page/[page].js
+++ b/pages/category/[category]/page/[page].js
@@ -44,11 +44,13 @@ export async function getStaticProps({ params: { category, page } }) {
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
@@ -69,7 +71,7 @@ export async function getStaticPaths() {
// 处理文章页数
const postCount = categoryPosts.length
const totalPages = Math.ceil(
- postCount / siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
+ postCount / siteConfig('POSTS_PER_PAGE', null, NOTION_CONFIG)
)
if (totalPages > 1) {
for (let i = 1; i <= totalPages; i++) {
diff --git a/pages/category/index.js b/pages/category/index.js
index 423383bf..62a3cc9f 100644
--- a/pages/category/index.js
+++ b/pages/category/index.js
@@ -24,10 +24,12 @@ export async function getStaticProps({ locale }) {
delete props.allPages
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/pages/index.js b/pages/index.js
index b925bc0e..43f5b114 100644
--- a/pages/index.js
+++ b/pages/index.js
@@ -69,11 +69,13 @@ export async function getStaticProps(req) {
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/pages/page/[page].js b/pages/page/[page].js
index 236c93ef..bd1dc7e2 100644
--- a/pages/page/[page].js
+++ b/pages/page/[page].js
@@ -23,7 +23,7 @@ export async function getStaticPaths({ locale }) {
const from = 'page-paths'
const { postCount, NOTION_CONFIG } = await getGlobalData({ from, locale })
const totalPages = Math.ceil(
- postCount / siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
+ postCount / siteConfig('POSTS_PER_PAGE', null, NOTION_CONFIG)
)
return {
// remove first page, we 're not gonna handle that.
@@ -69,11 +69,13 @@ export async function getStaticProps({ params: { page } }) {
delete props.allPages
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/pages/search/[keyword]/index.js b/pages/search/[keyword]/index.js
index 6d753578..9b491b00 100644
--- a/pages/search/[keyword]/index.js
+++ b/pages/search/[keyword]/index.js
@@ -47,11 +47,13 @@ export async function getStaticProps({ params: { keyword }, locale }) {
props.keyword = keyword
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/pages/search/[keyword]/page/[page].js b/pages/search/[keyword]/page/[page].js
index 6e497b7c..bebaa9fc 100644
--- a/pages/search/[keyword]/page/[page].js
+++ b/pages/search/[keyword]/page/[page].js
@@ -45,11 +45,13 @@ export async function getStaticProps({ params: { keyword, page }, locale }) {
delete props.allPages
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/pages/search/index.js b/pages/search/index.js
index 87d2e16d..6226a400 100644
--- a/pages/search/index.js
+++ b/pages/search/index.js
@@ -54,11 +54,13 @@ export async function getStaticProps({ locale }) {
)
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/pages/signin.js b/pages/signin.js
index b3a2765f..fbf618a4 100644
--- a/pages/signin.js
+++ b/pages/signin.js
@@ -27,11 +27,13 @@ export async function getStaticProps(req) {
delete props.allPages
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/pages/signup.js b/pages/signup.js
index d0852c4e..bbe38129 100644
--- a/pages/signup.js
+++ b/pages/signup.js
@@ -27,11 +27,13 @@ export async function getStaticProps(req) {
delete props.allPages
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/pages/sitemap.xml.js b/pages/sitemap.xml.js
index eb7f7bd8..2f6c20fe 100644
--- a/pages/sitemap.xml.js
+++ b/pages/sitemap.xml.js
@@ -27,7 +27,6 @@ export const getServerSideProps = async ctx => {
'Cache-Control',
'public, max-age=3600, stale-while-revalidate=59'
)
- console.log('fff', fields)
return getServerSideSitemap(ctx, fields)
}
@@ -55,7 +54,7 @@ function generateLocalesSitemap(link, allPages, locale) {
priority: '0.7'
},
{
- loc: `${link}${locale}/feed`,
+ loc: `${link}${locale}/rss/feed.xml`,
lastmod: new Date().toISOString().split('T')[0],
changefreq: 'daily',
priority: '0.7'
diff --git a/pages/tag/[tag]/index.js b/pages/tag/[tag]/index.js
index 2860f91c..79458257 100644
--- a/pages/tag/[tag]/index.js
+++ b/pages/tag/[tag]/index.js
@@ -45,11 +45,13 @@ export async function getStaticProps({ params: { tag }, locale }) {
delete props.allPages
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/pages/tag/[tag]/page/[page].js b/pages/tag/[tag]/page/[page].js
index f8e70c3c..da93f16f 100644
--- a/pages/tag/[tag]/page/[page].js
+++ b/pages/tag/[tag]/page/[page].js
@@ -34,11 +34,13 @@ export async function getStaticProps({ params: { tag, page }, locale }) {
delete props.allPages
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
@@ -54,7 +56,7 @@ export async function getStaticPaths() {
// 处理文章页数
const postCount = tagPosts.length
const totalPages = Math.ceil(
- postCount / siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
+ postCount / siteConfig('POSTS_PER_PAGE', null, NOTION_CONFIG)
)
if (totalPages > 1) {
for (let i = 1; i <= totalPages; i++) {
diff --git a/pages/tag/index.js b/pages/tag/index.js
index f9cddea4..5433a033 100644
--- a/pages/tag/index.js
+++ b/pages/tag/index.js
@@ -26,11 +26,13 @@ export async function getStaticProps(req) {
delete props.allPages
return {
props,
- revalidate: siteConfig(
- 'NEXT_REVALIDATE_SECOND',
- BLOG.NEXT_REVALIDATE_SECOND,
- props.NOTION_CONFIG
- )
+ revalidate: process.env.EXPORT
+ ? undefined
+ : siteConfig(
+ 'NEXT_REVALIDATE_SECOND',
+ BLOG.NEXT_REVALIDATE_SECOND,
+ props.NOTION_CONFIG
+ )
}
}
diff --git a/public/css/aos.css b/public/css/aos.css
new file mode 100644
index 00000000..86710a57
--- /dev/null
+++ b/public/css/aos.css
@@ -0,0 +1,916 @@
+[data-aos][data-aos][data-aos-duration='50'],
+body[data-aos-duration='50'] [data-aos] {
+ transition-duration: 50ms;
+}
+[data-aos][data-aos][data-aos-delay='50'],
+body[data-aos-delay='50'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='50'].aos-animate,
+body[data-aos-delay='50'] [data-aos].aos-animate {
+ transition-delay: 50ms;
+}
+[data-aos][data-aos][data-aos-duration='100'],
+body[data-aos-duration='100'] [data-aos] {
+ transition-duration: 0.1s;
+}
+[data-aos][data-aos][data-aos-delay='100'],
+body[data-aos-delay='100'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='100'].aos-animate,
+body[data-aos-delay='100'] [data-aos].aos-animate {
+ transition-delay: 0.1s;
+}
+[data-aos][data-aos][data-aos-duration='150'],
+body[data-aos-duration='150'] [data-aos] {
+ transition-duration: 0.15s;
+}
+[data-aos][data-aos][data-aos-delay='150'],
+body[data-aos-delay='150'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='150'].aos-animate,
+body[data-aos-delay='150'] [data-aos].aos-animate {
+ transition-delay: 0.15s;
+}
+[data-aos][data-aos][data-aos-duration='200'],
+body[data-aos-duration='200'] [data-aos] {
+ transition-duration: 0.2s;
+}
+[data-aos][data-aos][data-aos-delay='200'],
+body[data-aos-delay='200'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='200'].aos-animate,
+body[data-aos-delay='200'] [data-aos].aos-animate {
+ transition-delay: 0.2s;
+}
+[data-aos][data-aos][data-aos-duration='250'],
+body[data-aos-duration='250'] [data-aos] {
+ transition-duration: 0.25s;
+}
+[data-aos][data-aos][data-aos-delay='250'],
+body[data-aos-delay='250'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='250'].aos-animate,
+body[data-aos-delay='250'] [data-aos].aos-animate {
+ transition-delay: 0.25s;
+}
+[data-aos][data-aos][data-aos-duration='300'],
+body[data-aos-duration='300'] [data-aos] {
+ transition-duration: 0.3s;
+}
+[data-aos][data-aos][data-aos-delay='300'],
+body[data-aos-delay='300'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='300'].aos-animate,
+body[data-aos-delay='300'] [data-aos].aos-animate {
+ transition-delay: 0.3s;
+}
+[data-aos][data-aos][data-aos-duration='350'],
+body[data-aos-duration='350'] [data-aos] {
+ transition-duration: 0.35s;
+}
+[data-aos][data-aos][data-aos-delay='350'],
+body[data-aos-delay='350'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='350'].aos-animate,
+body[data-aos-delay='350'] [data-aos].aos-animate {
+ transition-delay: 0.35s;
+}
+[data-aos][data-aos][data-aos-duration='400'],
+body[data-aos-duration='400'] [data-aos] {
+ transition-duration: 0.4s;
+}
+[data-aos][data-aos][data-aos-delay='400'],
+body[data-aos-delay='400'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='400'].aos-animate,
+body[data-aos-delay='400'] [data-aos].aos-animate {
+ transition-delay: 0.4s;
+}
+[data-aos][data-aos][data-aos-duration='450'],
+body[data-aos-duration='450'] [data-aos] {
+ transition-duration: 0.45s;
+}
+[data-aos][data-aos][data-aos-delay='450'],
+body[data-aos-delay='450'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='450'].aos-animate,
+body[data-aos-delay='450'] [data-aos].aos-animate {
+ transition-delay: 0.45s;
+}
+[data-aos][data-aos][data-aos-duration='500'],
+body[data-aos-duration='500'] [data-aos] {
+ transition-duration: 0.5s;
+}
+[data-aos][data-aos][data-aos-delay='500'],
+body[data-aos-delay='500'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='500'].aos-animate,
+body[data-aos-delay='500'] [data-aos].aos-animate {
+ transition-delay: 0.5s;
+}
+[data-aos][data-aos][data-aos-duration='550'],
+body[data-aos-duration='550'] [data-aos] {
+ transition-duration: 0.55s;
+}
+[data-aos][data-aos][data-aos-delay='550'],
+body[data-aos-delay='550'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='550'].aos-animate,
+body[data-aos-delay='550'] [data-aos].aos-animate {
+ transition-delay: 0.55s;
+}
+[data-aos][data-aos][data-aos-duration='600'],
+body[data-aos-duration='600'] [data-aos] {
+ transition-duration: 0.6s;
+}
+[data-aos][data-aos][data-aos-delay='600'],
+body[data-aos-delay='600'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='600'].aos-animate,
+body[data-aos-delay='600'] [data-aos].aos-animate {
+ transition-delay: 0.6s;
+}
+[data-aos][data-aos][data-aos-duration='650'],
+body[data-aos-duration='650'] [data-aos] {
+ transition-duration: 0.65s;
+}
+[data-aos][data-aos][data-aos-delay='650'],
+body[data-aos-delay='650'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='650'].aos-animate,
+body[data-aos-delay='650'] [data-aos].aos-animate {
+ transition-delay: 0.65s;
+}
+[data-aos][data-aos][data-aos-duration='700'],
+body[data-aos-duration='700'] [data-aos] {
+ transition-duration: 0.7s;
+}
+[data-aos][data-aos][data-aos-delay='700'],
+body[data-aos-delay='700'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='700'].aos-animate,
+body[data-aos-delay='700'] [data-aos].aos-animate {
+ transition-delay: 0.7s;
+}
+[data-aos][data-aos][data-aos-duration='750'],
+body[data-aos-duration='750'] [data-aos] {
+ transition-duration: 0.75s;
+}
+[data-aos][data-aos][data-aos-delay='750'],
+body[data-aos-delay='750'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='750'].aos-animate,
+body[data-aos-delay='750'] [data-aos].aos-animate {
+ transition-delay: 0.75s;
+}
+[data-aos][data-aos][data-aos-duration='800'],
+body[data-aos-duration='800'] [data-aos] {
+ transition-duration: 0.8s;
+}
+[data-aos][data-aos][data-aos-delay='800'],
+body[data-aos-delay='800'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='800'].aos-animate,
+body[data-aos-delay='800'] [data-aos].aos-animate {
+ transition-delay: 0.8s;
+}
+[data-aos][data-aos][data-aos-duration='850'],
+body[data-aos-duration='850'] [data-aos] {
+ transition-duration: 0.85s;
+}
+[data-aos][data-aos][data-aos-delay='850'],
+body[data-aos-delay='850'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='850'].aos-animate,
+body[data-aos-delay='850'] [data-aos].aos-animate {
+ transition-delay: 0.85s;
+}
+[data-aos][data-aos][data-aos-duration='900'],
+body[data-aos-duration='900'] [data-aos] {
+ transition-duration: 0.9s;
+}
+[data-aos][data-aos][data-aos-delay='900'],
+body[data-aos-delay='900'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='900'].aos-animate,
+body[data-aos-delay='900'] [data-aos].aos-animate {
+ transition-delay: 0.9s;
+}
+[data-aos][data-aos][data-aos-duration='950'],
+body[data-aos-duration='950'] [data-aos] {
+ transition-duration: 0.95s;
+}
+[data-aos][data-aos][data-aos-delay='950'],
+body[data-aos-delay='950'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='950'].aos-animate,
+body[data-aos-delay='950'] [data-aos].aos-animate {
+ transition-delay: 0.95s;
+}
+[data-aos][data-aos][data-aos-duration='1000'],
+body[data-aos-duration='1000'] [data-aos] {
+ transition-duration: 1s;
+}
+[data-aos][data-aos][data-aos-delay='1000'],
+body[data-aos-delay='1000'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1000'].aos-animate,
+body[data-aos-delay='1000'] [data-aos].aos-animate {
+ transition-delay: 1s;
+}
+[data-aos][data-aos][data-aos-duration='1050'],
+body[data-aos-duration='1050'] [data-aos] {
+ transition-duration: 1.05s;
+}
+[data-aos][data-aos][data-aos-delay='1050'],
+body[data-aos-delay='1050'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1050'].aos-animate,
+body[data-aos-delay='1050'] [data-aos].aos-animate {
+ transition-delay: 1.05s;
+}
+[data-aos][data-aos][data-aos-duration='1100'],
+body[data-aos-duration='1100'] [data-aos] {
+ transition-duration: 1.1s;
+}
+[data-aos][data-aos][data-aos-delay='1100'],
+body[data-aos-delay='1100'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1100'].aos-animate,
+body[data-aos-delay='1100'] [data-aos].aos-animate {
+ transition-delay: 1.1s;
+}
+[data-aos][data-aos][data-aos-duration='1150'],
+body[data-aos-duration='1150'] [data-aos] {
+ transition-duration: 1.15s;
+}
+[data-aos][data-aos][data-aos-delay='1150'],
+body[data-aos-delay='1150'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1150'].aos-animate,
+body[data-aos-delay='1150'] [data-aos].aos-animate {
+ transition-delay: 1.15s;
+}
+[data-aos][data-aos][data-aos-duration='1200'],
+body[data-aos-duration='1200'] [data-aos] {
+ transition-duration: 1.2s;
+}
+[data-aos][data-aos][data-aos-delay='1200'],
+body[data-aos-delay='1200'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1200'].aos-animate,
+body[data-aos-delay='1200'] [data-aos].aos-animate {
+ transition-delay: 1.2s;
+}
+[data-aos][data-aos][data-aos-duration='1250'],
+body[data-aos-duration='1250'] [data-aos] {
+ transition-duration: 1.25s;
+}
+[data-aos][data-aos][data-aos-delay='1250'],
+body[data-aos-delay='1250'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1250'].aos-animate,
+body[data-aos-delay='1250'] [data-aos].aos-animate {
+ transition-delay: 1.25s;
+}
+[data-aos][data-aos][data-aos-duration='1300'],
+body[data-aos-duration='1300'] [data-aos] {
+ transition-duration: 1.3s;
+}
+[data-aos][data-aos][data-aos-delay='1300'],
+body[data-aos-delay='1300'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1300'].aos-animate,
+body[data-aos-delay='1300'] [data-aos].aos-animate {
+ transition-delay: 1.3s;
+}
+[data-aos][data-aos][data-aos-duration='1350'],
+body[data-aos-duration='1350'] [data-aos] {
+ transition-duration: 1.35s;
+}
+[data-aos][data-aos][data-aos-delay='1350'],
+body[data-aos-delay='1350'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1350'].aos-animate,
+body[data-aos-delay='1350'] [data-aos].aos-animate {
+ transition-delay: 1.35s;
+}
+[data-aos][data-aos][data-aos-duration='1400'],
+body[data-aos-duration='1400'] [data-aos] {
+ transition-duration: 1.4s;
+}
+[data-aos][data-aos][data-aos-delay='1400'],
+body[data-aos-delay='1400'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1400'].aos-animate,
+body[data-aos-delay='1400'] [data-aos].aos-animate {
+ transition-delay: 1.4s;
+}
+[data-aos][data-aos][data-aos-duration='1450'],
+body[data-aos-duration='1450'] [data-aos] {
+ transition-duration: 1.45s;
+}
+[data-aos][data-aos][data-aos-delay='1450'],
+body[data-aos-delay='1450'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1450'].aos-animate,
+body[data-aos-delay='1450'] [data-aos].aos-animate {
+ transition-delay: 1.45s;
+}
+[data-aos][data-aos][data-aos-duration='1500'],
+body[data-aos-duration='1500'] [data-aos] {
+ transition-duration: 1.5s;
+}
+[data-aos][data-aos][data-aos-delay='1500'],
+body[data-aos-delay='1500'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1500'].aos-animate,
+body[data-aos-delay='1500'] [data-aos].aos-animate {
+ transition-delay: 1.5s;
+}
+[data-aos][data-aos][data-aos-duration='1550'],
+body[data-aos-duration='1550'] [data-aos] {
+ transition-duration: 1.55s;
+}
+[data-aos][data-aos][data-aos-delay='1550'],
+body[data-aos-delay='1550'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1550'].aos-animate,
+body[data-aos-delay='1550'] [data-aos].aos-animate {
+ transition-delay: 1.55s;
+}
+[data-aos][data-aos][data-aos-duration='1600'],
+body[data-aos-duration='1600'] [data-aos] {
+ transition-duration: 1.6s;
+}
+[data-aos][data-aos][data-aos-delay='1600'],
+body[data-aos-delay='1600'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1600'].aos-animate,
+body[data-aos-delay='1600'] [data-aos].aos-animate {
+ transition-delay: 1.6s;
+}
+[data-aos][data-aos][data-aos-duration='1650'],
+body[data-aos-duration='1650'] [data-aos] {
+ transition-duration: 1.65s;
+}
+[data-aos][data-aos][data-aos-delay='1650'],
+body[data-aos-delay='1650'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1650'].aos-animate,
+body[data-aos-delay='1650'] [data-aos].aos-animate {
+ transition-delay: 1.65s;
+}
+[data-aos][data-aos][data-aos-duration='1700'],
+body[data-aos-duration='1700'] [data-aos] {
+ transition-duration: 1.7s;
+}
+[data-aos][data-aos][data-aos-delay='1700'],
+body[data-aos-delay='1700'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1700'].aos-animate,
+body[data-aos-delay='1700'] [data-aos].aos-animate {
+ transition-delay: 1.7s;
+}
+[data-aos][data-aos][data-aos-duration='1750'],
+body[data-aos-duration='1750'] [data-aos] {
+ transition-duration: 1.75s;
+}
+[data-aos][data-aos][data-aos-delay='1750'],
+body[data-aos-delay='1750'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1750'].aos-animate,
+body[data-aos-delay='1750'] [data-aos].aos-animate {
+ transition-delay: 1.75s;
+}
+[data-aos][data-aos][data-aos-duration='1800'],
+body[data-aos-duration='1800'] [data-aos] {
+ transition-duration: 1.8s;
+}
+[data-aos][data-aos][data-aos-delay='1800'],
+body[data-aos-delay='1800'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1800'].aos-animate,
+body[data-aos-delay='1800'] [data-aos].aos-animate {
+ transition-delay: 1.8s;
+}
+[data-aos][data-aos][data-aos-duration='1850'],
+body[data-aos-duration='1850'] [data-aos] {
+ transition-duration: 1.85s;
+}
+[data-aos][data-aos][data-aos-delay='1850'],
+body[data-aos-delay='1850'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1850'].aos-animate,
+body[data-aos-delay='1850'] [data-aos].aos-animate {
+ transition-delay: 1.85s;
+}
+[data-aos][data-aos][data-aos-duration='1900'],
+body[data-aos-duration='1900'] [data-aos] {
+ transition-duration: 1.9s;
+}
+[data-aos][data-aos][data-aos-delay='1900'],
+body[data-aos-delay='1900'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1900'].aos-animate,
+body[data-aos-delay='1900'] [data-aos].aos-animate {
+ transition-delay: 1.9s;
+}
+[data-aos][data-aos][data-aos-duration='1950'],
+body[data-aos-duration='1950'] [data-aos] {
+ transition-duration: 1.95s;
+}
+[data-aos][data-aos][data-aos-delay='1950'],
+body[data-aos-delay='1950'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='1950'].aos-animate,
+body[data-aos-delay='1950'] [data-aos].aos-animate {
+ transition-delay: 1.95s;
+}
+[data-aos][data-aos][data-aos-duration='2000'],
+body[data-aos-duration='2000'] [data-aos] {
+ transition-duration: 2s;
+}
+[data-aos][data-aos][data-aos-delay='2000'],
+body[data-aos-delay='2000'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2000'].aos-animate,
+body[data-aos-delay='2000'] [data-aos].aos-animate {
+ transition-delay: 2s;
+}
+[data-aos][data-aos][data-aos-duration='2050'],
+body[data-aos-duration='2050'] [data-aos] {
+ transition-duration: 2.05s;
+}
+[data-aos][data-aos][data-aos-delay='2050'],
+body[data-aos-delay='2050'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2050'].aos-animate,
+body[data-aos-delay='2050'] [data-aos].aos-animate {
+ transition-delay: 2.05s;
+}
+[data-aos][data-aos][data-aos-duration='2100'],
+body[data-aos-duration='2100'] [data-aos] {
+ transition-duration: 2.1s;
+}
+[data-aos][data-aos][data-aos-delay='2100'],
+body[data-aos-delay='2100'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2100'].aos-animate,
+body[data-aos-delay='2100'] [data-aos].aos-animate {
+ transition-delay: 2.1s;
+}
+[data-aos][data-aos][data-aos-duration='2150'],
+body[data-aos-duration='2150'] [data-aos] {
+ transition-duration: 2.15s;
+}
+[data-aos][data-aos][data-aos-delay='2150'],
+body[data-aos-delay='2150'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2150'].aos-animate,
+body[data-aos-delay='2150'] [data-aos].aos-animate {
+ transition-delay: 2.15s;
+}
+[data-aos][data-aos][data-aos-duration='2200'],
+body[data-aos-duration='2200'] [data-aos] {
+ transition-duration: 2.2s;
+}
+[data-aos][data-aos][data-aos-delay='2200'],
+body[data-aos-delay='2200'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2200'].aos-animate,
+body[data-aos-delay='2200'] [data-aos].aos-animate {
+ transition-delay: 2.2s;
+}
+[data-aos][data-aos][data-aos-duration='2250'],
+body[data-aos-duration='2250'] [data-aos] {
+ transition-duration: 2.25s;
+}
+[data-aos][data-aos][data-aos-delay='2250'],
+body[data-aos-delay='2250'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2250'].aos-animate,
+body[data-aos-delay='2250'] [data-aos].aos-animate {
+ transition-delay: 2.25s;
+}
+[data-aos][data-aos][data-aos-duration='2300'],
+body[data-aos-duration='2300'] [data-aos] {
+ transition-duration: 2.3s;
+}
+[data-aos][data-aos][data-aos-delay='2300'],
+body[data-aos-delay='2300'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2300'].aos-animate,
+body[data-aos-delay='2300'] [data-aos].aos-animate {
+ transition-delay: 2.3s;
+}
+[data-aos][data-aos][data-aos-duration='2350'],
+body[data-aos-duration='2350'] [data-aos] {
+ transition-duration: 2.35s;
+}
+[data-aos][data-aos][data-aos-delay='2350'],
+body[data-aos-delay='2350'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2350'].aos-animate,
+body[data-aos-delay='2350'] [data-aos].aos-animate {
+ transition-delay: 2.35s;
+}
+[data-aos][data-aos][data-aos-duration='2400'],
+body[data-aos-duration='2400'] [data-aos] {
+ transition-duration: 2.4s;
+}
+[data-aos][data-aos][data-aos-delay='2400'],
+body[data-aos-delay='2400'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2400'].aos-animate,
+body[data-aos-delay='2400'] [data-aos].aos-animate {
+ transition-delay: 2.4s;
+}
+[data-aos][data-aos][data-aos-duration='2450'],
+body[data-aos-duration='2450'] [data-aos] {
+ transition-duration: 2.45s;
+}
+[data-aos][data-aos][data-aos-delay='2450'],
+body[data-aos-delay='2450'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2450'].aos-animate,
+body[data-aos-delay='2450'] [data-aos].aos-animate {
+ transition-delay: 2.45s;
+}
+[data-aos][data-aos][data-aos-duration='2500'],
+body[data-aos-duration='2500'] [data-aos] {
+ transition-duration: 2.5s;
+}
+[data-aos][data-aos][data-aos-delay='2500'],
+body[data-aos-delay='2500'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2500'].aos-animate,
+body[data-aos-delay='2500'] [data-aos].aos-animate {
+ transition-delay: 2.5s;
+}
+[data-aos][data-aos][data-aos-duration='2550'],
+body[data-aos-duration='2550'] [data-aos] {
+ transition-duration: 2.55s;
+}
+[data-aos][data-aos][data-aos-delay='2550'],
+body[data-aos-delay='2550'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2550'].aos-animate,
+body[data-aos-delay='2550'] [data-aos].aos-animate {
+ transition-delay: 2.55s;
+}
+[data-aos][data-aos][data-aos-duration='2600'],
+body[data-aos-duration='2600'] [data-aos] {
+ transition-duration: 2.6s;
+}
+[data-aos][data-aos][data-aos-delay='2600'],
+body[data-aos-delay='2600'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2600'].aos-animate,
+body[data-aos-delay='2600'] [data-aos].aos-animate {
+ transition-delay: 2.6s;
+}
+[data-aos][data-aos][data-aos-duration='2650'],
+body[data-aos-duration='2650'] [data-aos] {
+ transition-duration: 2.65s;
+}
+[data-aos][data-aos][data-aos-delay='2650'],
+body[data-aos-delay='2650'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2650'].aos-animate,
+body[data-aos-delay='2650'] [data-aos].aos-animate {
+ transition-delay: 2.65s;
+}
+[data-aos][data-aos][data-aos-duration='2700'],
+body[data-aos-duration='2700'] [data-aos] {
+ transition-duration: 2.7s;
+}
+[data-aos][data-aos][data-aos-delay='2700'],
+body[data-aos-delay='2700'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2700'].aos-animate,
+body[data-aos-delay='2700'] [data-aos].aos-animate {
+ transition-delay: 2.7s;
+}
+[data-aos][data-aos][data-aos-duration='2750'],
+body[data-aos-duration='2750'] [data-aos] {
+ transition-duration: 2.75s;
+}
+[data-aos][data-aos][data-aos-delay='2750'],
+body[data-aos-delay='2750'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2750'].aos-animate,
+body[data-aos-delay='2750'] [data-aos].aos-animate {
+ transition-delay: 2.75s;
+}
+[data-aos][data-aos][data-aos-duration='2800'],
+body[data-aos-duration='2800'] [data-aos] {
+ transition-duration: 2.8s;
+}
+[data-aos][data-aos][data-aos-delay='2800'],
+body[data-aos-delay='2800'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2800'].aos-animate,
+body[data-aos-delay='2800'] [data-aos].aos-animate {
+ transition-delay: 2.8s;
+}
+[data-aos][data-aos][data-aos-duration='2850'],
+body[data-aos-duration='2850'] [data-aos] {
+ transition-duration: 2.85s;
+}
+[data-aos][data-aos][data-aos-delay='2850'],
+body[data-aos-delay='2850'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2850'].aos-animate,
+body[data-aos-delay='2850'] [data-aos].aos-animate {
+ transition-delay: 2.85s;
+}
+[data-aos][data-aos][data-aos-duration='2900'],
+body[data-aos-duration='2900'] [data-aos] {
+ transition-duration: 2.9s;
+}
+[data-aos][data-aos][data-aos-delay='2900'],
+body[data-aos-delay='2900'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2900'].aos-animate,
+body[data-aos-delay='2900'] [data-aos].aos-animate {
+ transition-delay: 2.9s;
+}
+[data-aos][data-aos][data-aos-duration='2950'],
+body[data-aos-duration='2950'] [data-aos] {
+ transition-duration: 2.95s;
+}
+[data-aos][data-aos][data-aos-delay='2950'],
+body[data-aos-delay='2950'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='2950'].aos-animate,
+body[data-aos-delay='2950'] [data-aos].aos-animate {
+ transition-delay: 2.95s;
+}
+[data-aos][data-aos][data-aos-duration='3000'],
+body[data-aos-duration='3000'] [data-aos] {
+ transition-duration: 3s;
+}
+[data-aos][data-aos][data-aos-delay='3000'],
+body[data-aos-delay='3000'] [data-aos] {
+ transition-delay: 0;
+}
+[data-aos][data-aos][data-aos-delay='3000'].aos-animate,
+body[data-aos-delay='3000'] [data-aos].aos-animate {
+ transition-delay: 3s;
+}
+[data-aos][data-aos][data-aos-easing='linear'],
+body[data-aos-easing='linear'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.25, 0.25, 0.75, 0.75);
+}
+[data-aos][data-aos][data-aos-easing='ease'],
+body[data-aos-easing='ease'] [data-aos] {
+ transition-timing-function: ease;
+}
+[data-aos][data-aos][data-aos-easing='ease-in'],
+body[data-aos-easing='ease-in'] [data-aos] {
+ transition-timing-function: ease-in;
+}
+[data-aos][data-aos][data-aos-easing='ease-out'],
+body[data-aos-easing='ease-out'] [data-aos] {
+ transition-timing-function: ease-out;
+}
+[data-aos][data-aos][data-aos-easing='ease-in-out'],
+body[data-aos-easing='ease-in-out'] [data-aos] {
+ transition-timing-function: ease-in-out;
+}
+[data-aos][data-aos][data-aos-easing='ease-in-back'],
+body[data-aos-easing='ease-in-back'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.6, -0.28, 0.735, 0.045);
+}
+[data-aos][data-aos][data-aos-easing='ease-out-back'],
+body[data-aos-easing='ease-out-back'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
+}
+[data-aos][data-aos][data-aos-easing='ease-in-out-back'],
+body[data-aos-easing='ease-in-out-back'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
+}
+[data-aos][data-aos][data-aos-easing='ease-in-sine'],
+body[data-aos-easing='ease-in-sine'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.47, 0, 0.745, 0.715);
+}
+[data-aos][data-aos][data-aos-easing='ease-out-sine'],
+body[data-aos-easing='ease-out-sine'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.39, 0.575, 0.565, 1);
+}
+[data-aos][data-aos][data-aos-easing='ease-in-out-sine'],
+body[data-aos-easing='ease-in-out-sine'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.445, 0.05, 0.55, 0.95);
+}
+[data-aos][data-aos][data-aos-easing='ease-in-quad'],
+body[data-aos-easing='ease-in-quad'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.55, 0.085, 0.68, 0.53);
+}
+[data-aos][data-aos][data-aos-easing='ease-out-quad'],
+body[data-aos-easing='ease-out-quad'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+}
+[data-aos][data-aos][data-aos-easing='ease-in-out-quad'],
+body[data-aos-easing='ease-in-out-quad'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+}
+[data-aos][data-aos][data-aos-easing='ease-in-cubic'],
+body[data-aos-easing='ease-in-cubic'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.55, 0.085, 0.68, 0.53);
+}
+[data-aos][data-aos][data-aos-easing='ease-out-cubic'],
+body[data-aos-easing='ease-out-cubic'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+}
+[data-aos][data-aos][data-aos-easing='ease-in-out-cubic'],
+body[data-aos-easing='ease-in-out-cubic'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+}
+[data-aos][data-aos][data-aos-easing='ease-in-quart'],
+body[data-aos-easing='ease-in-quart'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.55, 0.085, 0.68, 0.53);
+}
+[data-aos][data-aos][data-aos-easing='ease-out-quart'],
+body[data-aos-easing='ease-out-quart'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
+}
+[data-aos][data-aos][data-aos-easing='ease-in-out-quart'],
+body[data-aos-easing='ease-in-out-quart'] [data-aos] {
+ transition-timing-function: cubic-bezier(0.455, 0.03, 0.515, 0.955);
+}
+[data-aos^='fade'][data-aos^='fade'] {
+ opacity: 0;
+ transition-property: opacity, transform;
+}
+[data-aos^='fade'][data-aos^='fade'].aos-animate {
+ opacity: 1;
+ transform: translateZ(0);
+}
+[data-aos='fade-up'] {
+ transform: translate3d(0, 100px, 0);
+}
+[data-aos='fade-down'] {
+ transform: translate3d(0, -100px, 0);
+}
+[data-aos='fade-right'] {
+ transform: translate3d(-100px, 0, 0);
+}
+[data-aos='fade-left'] {
+ transform: translate3d(100px, 0, 0);
+}
+[data-aos='fade-up-right'] {
+ transform: translate3d(-100px, 100px, 0);
+}
+[data-aos='fade-up-left'] {
+ transform: translate3d(100px, 100px, 0);
+}
+[data-aos='fade-down-right'] {
+ transform: translate3d(-100px, -100px, 0);
+}
+[data-aos='fade-down-left'] {
+ transform: translate3d(100px, -100px, 0);
+}
+[data-aos^='zoom'][data-aos^='zoom'] {
+ opacity: 0;
+ transition-property: opacity, transform;
+}
+[data-aos^='zoom'][data-aos^='zoom'].aos-animate {
+ opacity: 1;
+ transform: translateZ(0) scale(1);
+}
+[data-aos='zoom-in'] {
+ transform: scale(0.6);
+}
+[data-aos='zoom-in-up'] {
+ transform: translate3d(0, 100px, 0) scale(0.6);
+}
+[data-aos='zoom-in-down'] {
+ transform: translate3d(0, -100px, 0) scale(0.6);
+}
+[data-aos='zoom-in-right'] {
+ transform: translate3d(-100px, 0, 0) scale(0.6);
+}
+[data-aos='zoom-in-left'] {
+ transform: translate3d(100px, 0, 0) scale(0.6);
+}
+[data-aos='zoom-out'] {
+ transform: scale(1.2);
+}
+[data-aos='zoom-out-up'] {
+ transform: translate3d(0, 100px, 0) scale(1.2);
+}
+[data-aos='zoom-out-down'] {
+ transform: translate3d(0, -100px, 0) scale(1.2);
+}
+[data-aos='zoom-out-right'] {
+ transform: translate3d(-100px, 0, 0) scale(1.2);
+}
+[data-aos='zoom-out-left'] {
+ transform: translate3d(100px, 0, 0) scale(1.2);
+}
+[data-aos^='slide'][data-aos^='slide'] {
+ transition-property: transform;
+}
+[data-aos^='slide'][data-aos^='slide'].aos-animate {
+ transform: translateZ(0);
+}
+[data-aos='slide-up'] {
+ transform: translate3d(0, 100%, 0);
+}
+[data-aos='slide-down'] {
+ transform: translate3d(0, -100%, 0);
+}
+[data-aos='slide-right'] {
+ transform: translate3d(-100%, 0, 0);
+}
+[data-aos='slide-left'] {
+ transform: translate3d(100%, 0, 0);
+}
+[data-aos^='flip'][data-aos^='flip'] {
+ backface-visibility: hidden;
+ transition-property: transform;
+}
+[data-aos='flip-left'] {
+ transform: perspective(2500px) rotateY(-100deg);
+}
+[data-aos='flip-left'].aos-animate {
+ transform: perspective(2500px) rotateY(0);
+}
+[data-aos='flip-right'] {
+ transform: perspective(2500px) rotateY(100deg);
+}
+[data-aos='flip-right'].aos-animate {
+ transform: perspective(2500px) rotateY(0);
+}
+[data-aos='flip-up'] {
+ transform: perspective(2500px) rotateX(-100deg);
+}
+[data-aos='flip-up'].aos-animate {
+ transform: perspective(2500px) rotateX(0);
+}
+[data-aos='flip-down'] {
+ transform: perspective(2500px) rotateX(100deg);
+}
+[data-aos='flip-down'].aos-animate {
+ transform: perspective(2500px) rotateX(0);
+}
diff --git a/public/js/aos.js b/public/js/aos.js
new file mode 100644
index 00000000..f77369b7
--- /dev/null
+++ b/public/js/aos.js
@@ -0,0 +1,672 @@
+!(function (e, t) {
+ 'object' == typeof exports && 'object' == typeof module
+ ? (module.exports = t())
+ : 'function' == typeof define && define.amd
+ ? define([], t)
+ : 'object' == typeof exports
+ ? (exports.AOS = t())
+ : (e.AOS = t())
+})(this, function () {
+ return (function (e) {
+ function t(o) {
+ if (n[o]) return n[o].exports
+ var i = (n[o] = { exports: {}, id: o, loaded: !1 })
+ return e[o].call(i.exports, i, i.exports, t), (i.loaded = !0), i.exports
+ }
+ var n = {}
+ return (t.m = e), (t.c = n), (t.p = 'dist/'), t(0)
+ })([
+ function (e, t, n) {
+ 'use strict'
+ function o(e) {
+ return e && e.__esModule ? e : { default: e }
+ }
+ var i =
+ Object.assign ||
+ function (e) {
+ for (var t = 1; t < arguments.length; t++) {
+ var n = arguments[t]
+ for (var o in n)
+ Object.prototype.hasOwnProperty.call(n, o) && (e[o] = n[o])
+ }
+ return e
+ },
+ r = n(1),
+ a = (o(r), n(6)),
+ u = o(a),
+ c = n(7),
+ s = o(c),
+ f = n(8),
+ d = o(f),
+ l = n(9),
+ p = o(l),
+ m = n(10),
+ b = o(m),
+ v = n(11),
+ y = o(v),
+ g = n(14),
+ h = o(g),
+ w = [],
+ k = !1,
+ x = {
+ offset: 120,
+ delay: 0,
+ easing: 'ease',
+ duration: 400,
+ disable: !1,
+ once: !1,
+ startEvent: 'DOMContentLoaded',
+ throttleDelay: 99,
+ debounceDelay: 50,
+ disableMutationObserver: !1
+ },
+ j = function () {
+ var e =
+ arguments.length > 0 && void 0 !== arguments[0] && arguments[0]
+ if ((e && (k = !0), k))
+ return (w = (0, y.default)(w, x)), (0, b.default)(w, x.once), w
+ },
+ O = function () {
+ ;(w = (0, h.default)()), j()
+ },
+ M = function () {
+ w.forEach(function (e, t) {
+ e.node.removeAttribute('data-aos'),
+ e.node.removeAttribute('data-aos-easing'),
+ e.node.removeAttribute('data-aos-duration'),
+ e.node.removeAttribute('data-aos-delay')
+ })
+ },
+ S = function (e) {
+ return (
+ e === !0 ||
+ ('mobile' === e && p.default.mobile()) ||
+ ('phone' === e && p.default.phone()) ||
+ ('tablet' === e && p.default.tablet()) ||
+ ('function' == typeof e && e() === !0)
+ )
+ },
+ _ = function (e) {
+ ;(x = i(x, e)), (w = (0, h.default)())
+ var t = document.all && !window.atob
+ return S(x.disable) || t
+ ? M()
+ : (x.disableMutationObserver ||
+ d.default.isSupported() ||
+ (console.info(
+ '\n aos: MutationObserver is not supported on this browser,\n code mutations observing has been disabled.\n You may have to call "refreshHard()" by yourself.\n '
+ ),
+ (x.disableMutationObserver = !0)),
+ document
+ .querySelector('body')
+ .setAttribute('data-aos-easing', x.easing),
+ document
+ .querySelector('body')
+ .setAttribute('data-aos-duration', x.duration),
+ document
+ .querySelector('body')
+ .setAttribute('data-aos-delay', x.delay),
+ 'DOMContentLoaded' === x.startEvent &&
+ ['complete', 'interactive'].indexOf(document.readyState) > -1
+ ? j(!0)
+ : 'load' === x.startEvent
+ ? window.addEventListener(x.startEvent, function () {
+ j(!0)
+ })
+ : document.addEventListener(x.startEvent, function () {
+ j(!0)
+ }),
+ window.addEventListener(
+ 'resize',
+ (0, s.default)(j, x.debounceDelay, !0)
+ ),
+ window.addEventListener(
+ 'orientationchange',
+ (0, s.default)(j, x.debounceDelay, !0)
+ ),
+ window.addEventListener(
+ 'scroll',
+ (0, u.default)(function () {
+ ;(0, b.default)(w, x.once)
+ }, x.throttleDelay)
+ ),
+ x.disableMutationObserver || d.default.ready('[data-aos]', O),
+ w)
+ }
+ e.exports = { init: _, refresh: j, refreshHard: O }
+ },
+ function (e, t) {},
+ ,
+ ,
+ ,
+ ,
+ function (e, t) {
+ ;(function (t) {
+ 'use strict'
+ function n(e, t, n) {
+ function o(t) {
+ var n = b,
+ o = v
+ return (b = v = void 0), (k = t), (g = e.apply(o, n))
+ }
+ function r(e) {
+ return (k = e), (h = setTimeout(f, t)), M ? o(e) : g
+ }
+ function a(e) {
+ var n = e - w,
+ o = e - k,
+ i = t - n
+ return S ? j(i, y - o) : i
+ }
+ function c(e) {
+ var n = e - w,
+ o = e - k
+ return void 0 === w || n >= t || n < 0 || (S && o >= y)
+ }
+ function f() {
+ var e = O()
+ return c(e) ? d(e) : void (h = setTimeout(f, a(e)))
+ }
+ function d(e) {
+ return (h = void 0), _ && b ? o(e) : ((b = v = void 0), g)
+ }
+ function l() {
+ void 0 !== h && clearTimeout(h), (k = 0), (b = w = v = h = void 0)
+ }
+ function p() {
+ return void 0 === h ? g : d(O())
+ }
+ function m() {
+ var e = O(),
+ n = c(e)
+ if (((b = arguments), (v = this), (w = e), n)) {
+ if (void 0 === h) return r(w)
+ if (S) return (h = setTimeout(f, t)), o(w)
+ }
+ return void 0 === h && (h = setTimeout(f, t)), g
+ }
+ var b,
+ v,
+ y,
+ g,
+ h,
+ w,
+ k = 0,
+ M = !1,
+ S = !1,
+ _ = !0
+ if ('function' != typeof e) throw new TypeError(s)
+ return (
+ (t = u(t) || 0),
+ i(n) &&
+ ((M = !!n.leading),
+ (S = 'maxWait' in n),
+ (y = S ? x(u(n.maxWait) || 0, t) : y),
+ (_ = 'trailing' in n ? !!n.trailing : _)),
+ (m.cancel = l),
+ (m.flush = p),
+ m
+ )
+ }
+ function o(e, t, o) {
+ var r = !0,
+ a = !0
+ if ('function' != typeof e) throw new TypeError(s)
+ return (
+ i(o) &&
+ ((r = 'leading' in o ? !!o.leading : r),
+ (a = 'trailing' in o ? !!o.trailing : a)),
+ n(e, t, { leading: r, maxWait: t, trailing: a })
+ )
+ }
+ function i(e) {
+ var t = 'undefined' == typeof e ? 'undefined' : c(e)
+ return !!e && ('object' == t || 'function' == t)
+ }
+ function r(e) {
+ return (
+ !!e && 'object' == ('undefined' == typeof e ? 'undefined' : c(e))
+ )
+ }
+ function a(e) {
+ return (
+ 'symbol' == ('undefined' == typeof e ? 'undefined' : c(e)) ||
+ (r(e) && k.call(e) == d)
+ )
+ }
+ function u(e) {
+ if ('number' == typeof e) return e
+ if (a(e)) return f
+ if (i(e)) {
+ var t = 'function' == typeof e.valueOf ? e.valueOf() : e
+ e = i(t) ? t + '' : t
+ }
+ if ('string' != typeof e) return 0 === e ? e : +e
+ e = e.replace(l, '')
+ var n = m.test(e)
+ return n || b.test(e) ? v(e.slice(2), n ? 2 : 8) : p.test(e) ? f : +e
+ }
+ var c =
+ 'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator
+ ? function (e) {
+ return typeof e
+ }
+ : function (e) {
+ return e &&
+ 'function' == typeof Symbol &&
+ e.constructor === Symbol &&
+ e !== Symbol.prototype
+ ? 'symbol'
+ : typeof e
+ },
+ s = 'Expected a function',
+ f = NaN,
+ d = '[object Symbol]',
+ l = /^\s+|\s+$/g,
+ p = /^[-+]0x[0-9a-f]+$/i,
+ m = /^0b[01]+$/i,
+ b = /^0o[0-7]+$/i,
+ v = parseInt,
+ y =
+ 'object' == ('undefined' == typeof t ? 'undefined' : c(t)) &&
+ t &&
+ t.Object === Object &&
+ t,
+ g =
+ 'object' == ('undefined' == typeof self ? 'undefined' : c(self)) &&
+ self &&
+ self.Object === Object &&
+ self,
+ h = y || g || Function('return this')(),
+ w = Object.prototype,
+ k = w.toString,
+ x = Math.max,
+ j = Math.min,
+ O = function () {
+ return h.Date.now()
+ }
+ e.exports = o
+ }).call(
+ t,
+ (function () {
+ return this
+ })()
+ )
+ },
+ function (e, t) {
+ ;(function (t) {
+ 'use strict'
+ function n(e, t, n) {
+ function i(t) {
+ var n = b,
+ o = v
+ return (b = v = void 0), (O = t), (g = e.apply(o, n))
+ }
+ function r(e) {
+ return (O = e), (h = setTimeout(f, t)), M ? i(e) : g
+ }
+ function u(e) {
+ var n = e - w,
+ o = e - O,
+ i = t - n
+ return S ? x(i, y - o) : i
+ }
+ function s(e) {
+ var n = e - w,
+ o = e - O
+ return void 0 === w || n >= t || n < 0 || (S && o >= y)
+ }
+ function f() {
+ var e = j()
+ return s(e) ? d(e) : void (h = setTimeout(f, u(e)))
+ }
+ function d(e) {
+ return (h = void 0), _ && b ? i(e) : ((b = v = void 0), g)
+ }
+ function l() {
+ void 0 !== h && clearTimeout(h), (O = 0), (b = w = v = h = void 0)
+ }
+ function p() {
+ return void 0 === h ? g : d(j())
+ }
+ function m() {
+ var e = j(),
+ n = s(e)
+ if (((b = arguments), (v = this), (w = e), n)) {
+ if (void 0 === h) return r(w)
+ if (S) return (h = setTimeout(f, t)), i(w)
+ }
+ return void 0 === h && (h = setTimeout(f, t)), g
+ }
+ var b,
+ v,
+ y,
+ g,
+ h,
+ w,
+ O = 0,
+ M = !1,
+ S = !1,
+ _ = !0
+ if ('function' != typeof e) throw new TypeError(c)
+ return (
+ (t = a(t) || 0),
+ o(n) &&
+ ((M = !!n.leading),
+ (S = 'maxWait' in n),
+ (y = S ? k(a(n.maxWait) || 0, t) : y),
+ (_ = 'trailing' in n ? !!n.trailing : _)),
+ (m.cancel = l),
+ (m.flush = p),
+ m
+ )
+ }
+ function o(e) {
+ var t = 'undefined' == typeof e ? 'undefined' : u(e)
+ return !!e && ('object' == t || 'function' == t)
+ }
+ function i(e) {
+ return (
+ !!e && 'object' == ('undefined' == typeof e ? 'undefined' : u(e))
+ )
+ }
+ function r(e) {
+ return (
+ 'symbol' == ('undefined' == typeof e ? 'undefined' : u(e)) ||
+ (i(e) && w.call(e) == f)
+ )
+ }
+ function a(e) {
+ if ('number' == typeof e) return e
+ if (r(e)) return s
+ if (o(e)) {
+ var t = 'function' == typeof e.valueOf ? e.valueOf() : e
+ e = o(t) ? t + '' : t
+ }
+ if ('string' != typeof e) return 0 === e ? e : +e
+ e = e.replace(d, '')
+ var n = p.test(e)
+ return n || m.test(e) ? b(e.slice(2), n ? 2 : 8) : l.test(e) ? s : +e
+ }
+ var u =
+ 'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator
+ ? function (e) {
+ return typeof e
+ }
+ : function (e) {
+ return e &&
+ 'function' == typeof Symbol &&
+ e.constructor === Symbol &&
+ e !== Symbol.prototype
+ ? 'symbol'
+ : typeof e
+ },
+ c = 'Expected a function',
+ s = NaN,
+ f = '[object Symbol]',
+ d = /^\s+|\s+$/g,
+ l = /^[-+]0x[0-9a-f]+$/i,
+ p = /^0b[01]+$/i,
+ m = /^0o[0-7]+$/i,
+ b = parseInt,
+ v =
+ 'object' == ('undefined' == typeof t ? 'undefined' : u(t)) &&
+ t &&
+ t.Object === Object &&
+ t,
+ y =
+ 'object' == ('undefined' == typeof self ? 'undefined' : u(self)) &&
+ self &&
+ self.Object === Object &&
+ self,
+ g = v || y || Function('return this')(),
+ h = Object.prototype,
+ w = h.toString,
+ k = Math.max,
+ x = Math.min,
+ j = function () {
+ return g.Date.now()
+ }
+ e.exports = n
+ }).call(
+ t,
+ (function () {
+ return this
+ })()
+ )
+ },
+ function (e, t) {
+ 'use strict'
+ function n(e) {
+ var t = void 0,
+ o = void 0,
+ i = void 0
+ for (t = 0; t < e.length; t += 1) {
+ if (((o = e[t]), o.dataset && o.dataset.aos)) return !0
+ if ((i = o.children && n(o.children))) return !0
+ }
+ return !1
+ }
+ function o() {
+ return (
+ window.MutationObserver ||
+ window.WebKitMutationObserver ||
+ window.MozMutationObserver
+ )
+ }
+ function i() {
+ return !!o()
+ }
+ function r(e, t) {
+ var n = window.document,
+ i = o(),
+ r = new i(a)
+ ;(u = t),
+ r.observe(n.documentElement, {
+ childList: !0,
+ subtree: !0,
+ removedNodes: !0
+ })
+ }
+ function a(e) {
+ e &&
+ e.forEach(function (e) {
+ var t = Array.prototype.slice.call(e.addedNodes),
+ o = Array.prototype.slice.call(e.removedNodes),
+ i = t.concat(o)
+ if (n(i)) return u()
+ })
+ }
+ Object.defineProperty(t, '__esModule', { value: !0 })
+ var u = function () {}
+ t.default = { isSupported: i, ready: r }
+ },
+ function (e, t) {
+ 'use strict'
+ function n(e, t) {
+ if (!(e instanceof t))
+ throw new TypeError('Cannot call a class as a function')
+ }
+ function o() {
+ return navigator.userAgent || navigator.vendor || window.opera || ''
+ }
+ Object.defineProperty(t, '__esModule', { value: !0 })
+ var i = (function () {
+ function e(e, t) {
+ for (var n = 0; n < t.length; n++) {
+ var o = t[n]
+ ;(o.enumerable = o.enumerable || !1),
+ (o.configurable = !0),
+ 'value' in o && (o.writable = !0),
+ Object.defineProperty(e, o.key, o)
+ }
+ }
+ return function (t, n, o) {
+ return n && e(t.prototype, n), o && e(t, o), t
+ }
+ })(),
+ r =
+ /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i,
+ a =
+ /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i,
+ u =
+ /(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i,
+ c =
+ /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i,
+ s = (function () {
+ function e() {
+ n(this, e)
+ }
+ return (
+ i(e, [
+ {
+ key: 'phone',
+ value: function () {
+ var e = o()
+ return !(!r.test(e) && !a.test(e.substr(0, 4)))
+ }
+ },
+ {
+ key: 'mobile',
+ value: function () {
+ var e = o()
+ return !(!u.test(e) && !c.test(e.substr(0, 4)))
+ }
+ },
+ {
+ key: 'tablet',
+ value: function () {
+ return this.mobile() && !this.phone()
+ }
+ }
+ ]),
+ e
+ )
+ })()
+ t.default = new s()
+ },
+ function (e, t) {
+ 'use strict'
+ Object.defineProperty(t, '__esModule', { value: !0 })
+ var n = function (e, t, n) {
+ var o = e.node.getAttribute('data-aos-once')
+ t > e.position
+ ? e.node.classList.add('aos-animate')
+ : 'undefined' != typeof o &&
+ ('false' === o || (!n && 'true' !== o)) &&
+ e.node.classList.remove('aos-animate')
+ },
+ o = function (e, t) {
+ var o = window.pageYOffset,
+ i = window.innerHeight
+ e.forEach(function (e, r) {
+ n(e, i + o, t)
+ })
+ }
+ t.default = o
+ },
+ function (e, t, n) {
+ 'use strict'
+ function o(e) {
+ return e && e.__esModule ? e : { default: e }
+ }
+ Object.defineProperty(t, '__esModule', { value: !0 })
+ var i = n(12),
+ r = o(i),
+ a = function (e, t) {
+ return (
+ e.forEach(function (e, n) {
+ e.node.classList.add('aos-init'),
+ (e.position = (0, r.default)(e.node, t.offset))
+ }),
+ e
+ )
+ }
+ t.default = a
+ },
+ function (e, t, n) {
+ 'use strict'
+ function o(e) {
+ return e && e.__esModule ? e : { default: e }
+ }
+ Object.defineProperty(t, '__esModule', { value: !0 })
+ var i = n(13),
+ r = o(i),
+ a = function (e, t) {
+ var n = 0,
+ o = 0,
+ i = window.innerHeight,
+ a = {
+ offset: e.getAttribute('data-aos-offset'),
+ anchor: e.getAttribute('data-aos-anchor'),
+ anchorPlacement: e.getAttribute('data-aos-anchor-placement')
+ }
+ switch (
+ (a.offset && !isNaN(a.offset) && (o = parseInt(a.offset)),
+ a.anchor &&
+ document.querySelectorAll(a.anchor) &&
+ (e = document.querySelectorAll(a.anchor)[0]),
+ (n = (0, r.default)(e).top),
+ a.anchorPlacement)
+ ) {
+ case 'top-bottom':
+ break
+ case 'center-bottom':
+ n += e.offsetHeight / 2
+ break
+ case 'bottom-bottom':
+ n += e.offsetHeight
+ break
+ case 'top-center':
+ n += i / 2
+ break
+ case 'bottom-center':
+ n += i / 2 + e.offsetHeight
+ break
+ case 'center-center':
+ n += i / 2 + e.offsetHeight / 2
+ break
+ case 'top-top':
+ n += i
+ break
+ case 'bottom-top':
+ n += e.offsetHeight + i
+ break
+ case 'center-top':
+ n += e.offsetHeight / 2 + i
+ }
+ return a.anchorPlacement || a.offset || isNaN(t) || (o = t), n + o
+ }
+ t.default = a
+ },
+ function (e, t) {
+ 'use strict'
+ Object.defineProperty(t, '__esModule', { value: !0 })
+ var n = function (e) {
+ for (
+ var t = 0, n = 0;
+ e && !isNaN(e.offsetLeft) && !isNaN(e.offsetTop);
+
+ )
+ (t += e.offsetLeft - ('BODY' != e.tagName ? e.scrollLeft : 0)),
+ (n += e.offsetTop - ('BODY' != e.tagName ? e.scrollTop : 0)),
+ (e = e.offsetParent)
+ return { top: n, left: t }
+ }
+ t.default = n
+ },
+ function (e, t) {
+ 'use strict'
+ Object.defineProperty(t, '__esModule', { value: !0 })
+ var n = function (e) {
+ return (
+ (e = e || document.querySelectorAll('[data-aos]')),
+ Array.prototype.map.call(e, function (e) {
+ return { node: e }
+ })
+ )
+ }
+ t.default = n
+ }
+ ])
+})
diff --git a/public/js/fireworks.js b/public/js/fireworks.js
index 937f9bf3..f1e8b4c9 100644
--- a/public/js/fireworks.js
+++ b/public/js/fireworks.js
@@ -57,10 +57,10 @@ function createFireworks({ config, anime }) {
function updateCoords(e) {
pointerX =
e.clientX ||
- (e.touches[0] ? e.touches[0].clientX : e.changedTouches[0].clientX)
+ (e?.touches[0] ? e.touches[0].clientX : e.changedTouches[0].clientX)
pointerY =
e.clientY ||
- (e.touches[0] ? e.touches[0].clientY : e.changedTouches[0].clientY)
+ (e?.touches[0] ? e.touches[0].clientY : e.changedTouches[0].clientY)
}
function setParticuleDirection(p) {
diff --git a/public/js/sakura.js b/public/js/sakura.js
index fcdf0739..ae018338 100644
--- a/public/js/sakura.js
+++ b/public/js/sakura.js
@@ -123,7 +123,7 @@ function createSakura() {
'style',
'position: fixed;left: 0;top: 0;pointer-events: none;'
)
- canvas.setAttribute('id', id)
+ canvas.setAttribute('id', 'sakura')
document.getElementsByTagName('body')[0].appendChild(canvas)
cxt = canvas.getContext('2d')
var sakuraList = new SakuraList()
@@ -185,4 +185,4 @@ function destroySakura() {
}
window.createSakura = createSakura
-window.destroySakura = destroySakura
\ No newline at end of file
+window.destroySakura = destroySakura
diff --git a/public/js/typed.min.js b/public/js/typed.min.js
new file mode 100644
index 00000000..52411da8
--- /dev/null
+++ b/public/js/typed.min.js
@@ -0,0 +1,626 @@
+/*!
+ *
+ * typed.js - A JavaScript Typing Animation Library
+ * Author: Matt Boldt
+ * Version: v2.0.12
+ * Url: https://github.com/mattboldt/typed.js
+ * License(s): MIT
+ *
+ */
+;(function (t, e) {
+ 'object' == typeof exports && 'object' == typeof module
+ ? (module.exports = e())
+ : 'function' == typeof define && define.amd
+ ? define([], e)
+ : 'object' == typeof exports
+ ? (exports.Typed = e())
+ : (t.Typed = e())
+})(this, function () {
+ return (function (t) {
+ function e(n) {
+ if (s[n]) return s[n].exports
+ var i = (s[n] = { exports: {}, id: n, loaded: !1 })
+ return t[n].call(i.exports, i, i.exports, e), (i.loaded = !0), i.exports
+ }
+ var s = {}
+ return (e.m = t), (e.c = s), (e.p = ''), e(0)
+ })([
+ function (t, e, s) {
+ 'use strict'
+ function n(t, e) {
+ if (!(t instanceof e))
+ throw new TypeError('Cannot call a class as a function')
+ }
+ Object.defineProperty(e, '__esModule', { value: !0 })
+ var i = (function () {
+ function t(t, e) {
+ for (var s = 0; s < e.length; s++) {
+ var n = e[s]
+ ;(n.enumerable = n.enumerable || !1),
+ (n.configurable = !0),
+ 'value' in n && (n.writable = !0),
+ Object.defineProperty(t, n.key, n)
+ }
+ }
+ return function (e, s, n) {
+ return s && t(e.prototype, s), n && t(e, n), e
+ }
+ })(),
+ r = s(1),
+ o = s(3),
+ a = (function () {
+ function t(e, s) {
+ n(this, t), r.initializer.load(this, s, e), this.begin()
+ }
+ return (
+ i(t, [
+ {
+ key: 'toggle',
+ value: function () {
+ this.pause.status ? this.start() : this.stop()
+ }
+ },
+ {
+ key: 'stop',
+ value: function () {
+ this.typingComplete ||
+ this.pause.status ||
+ (this.toggleBlinking(!0),
+ (this.pause.status = !0),
+ this.options.onStop(this.arrayPos, this))
+ }
+ },
+ {
+ key: 'start',
+ value: function () {
+ this.typingComplete ||
+ (this.pause.status &&
+ ((this.pause.status = !1),
+ this.pause.typewrite
+ ? this.typewrite(
+ this.pause.curString,
+ this.pause.curStrPos
+ )
+ : this.backspace(
+ this.pause.curString,
+ this.pause.curStrPos
+ ),
+ this.options.onStart(this.arrayPos, this)))
+ }
+ },
+ {
+ key: 'destroy',
+ value: function () {
+ this.reset(!1), this.options.onDestroy(this)
+ }
+ },
+ {
+ key: 'reset',
+ value: function () {
+ var t =
+ arguments.length <= 0 ||
+ void 0 === arguments[0] ||
+ arguments[0]
+ clearInterval(this.timeout),
+ this.replaceText(''),
+ this.cursor &&
+ this.cursor.parentNode &&
+ (this.cursor.parentNode.removeChild(this.cursor),
+ (this.cursor = null)),
+ (this.strPos = 0),
+ (this.arrayPos = 0),
+ (this.curLoop = 0),
+ t &&
+ (this.insertCursor(),
+ this.options.onReset(this),
+ this.begin())
+ }
+ },
+ {
+ key: 'begin',
+ value: function () {
+ var t = this
+ this.options.onBegin(this),
+ (this.typingComplete = !1),
+ this.shuffleStringsIfNeeded(this),
+ this.insertCursor(),
+ this.bindInputFocusEvents && this.bindFocusEvents(),
+ (this.timeout = setTimeout(function () {
+ t.currentElContent && 0 !== t.currentElContent.length
+ ? t.backspace(
+ t.currentElContent,
+ t.currentElContent.length
+ )
+ : t.typewrite(
+ t.strings[t.sequence[t.arrayPos]],
+ t.strPos
+ )
+ }, this.startDelay))
+ }
+ },
+ {
+ key: 'typewrite',
+ value: function (t, e) {
+ var s = this
+ this.fadeOut &&
+ this.el.classList.contains(this.fadeOutClass) &&
+ (this.el.classList.remove(this.fadeOutClass),
+ this.cursor &&
+ this.cursor.classList.remove(this.fadeOutClass))
+ var n = this.humanizer(this.typeSpeed),
+ i = 1
+ return this.pause.status === !0
+ ? void this.setPauseStatus(t, e, !0)
+ : void (this.timeout = setTimeout(function () {
+ e = o.htmlParser.typeHtmlChars(t, e, s)
+ var n = 0,
+ r = t.substr(e)
+ if ('^' === r.charAt(0) && /^\^\d+/.test(r)) {
+ var a = 1
+ ;(r = /\d+/.exec(r)[0]),
+ (a += r.length),
+ (n = parseInt(r)),
+ (s.temporaryPause = !0),
+ s.options.onTypingPaused(s.arrayPos, s),
+ (t = t.substring(0, e) + t.substring(e + a)),
+ s.toggleBlinking(!0)
+ }
+ if ('`' === r.charAt(0)) {
+ for (
+ ;
+ '`' !== t.substr(e + i).charAt(0) &&
+ (i++, !(e + i > t.length));
+
+ );
+ var u = t.substring(0, e),
+ l = t.substring(u.length + 1, e + i),
+ c = t.substring(e + i + 1)
+ ;(t = u + l + c), i--
+ }
+ s.timeout = setTimeout(function () {
+ s.toggleBlinking(!1),
+ e >= t.length
+ ? s.doneTyping(t, e)
+ : s.keepTyping(t, e, i),
+ s.temporaryPause &&
+ ((s.temporaryPause = !1),
+ s.options.onTypingResumed(s.arrayPos, s))
+ }, n)
+ }, n))
+ }
+ },
+ {
+ key: 'keepTyping',
+ value: function (t, e, s) {
+ 0 === e &&
+ (this.toggleBlinking(!1),
+ this.options.preStringTyped(this.arrayPos, this)),
+ (e += s)
+ var n = t.substr(0, e)
+ this.replaceText(n), this.typewrite(t, e)
+ }
+ },
+ {
+ key: 'doneTyping',
+ value: function (t, e) {
+ var s = this
+ this.options.onStringTyped(this.arrayPos, this),
+ this.toggleBlinking(!0),
+ (this.arrayPos === this.strings.length - 1 &&
+ (this.complete(),
+ this.loop === !1 || this.curLoop === this.loopCount)) ||
+ (this.timeout = setTimeout(function () {
+ s.backspace(t, e)
+ }, this.backDelay))
+ }
+ },
+ {
+ key: 'backspace',
+ value: function (t, e) {
+ var s = this
+ if (this.pause.status === !0)
+ return void this.setPauseStatus(t, e, !1)
+ if (this.fadeOut) return this.initFadeOut()
+ this.toggleBlinking(!1)
+ var n = this.humanizer(this.backSpeed)
+ this.timeout = setTimeout(function () {
+ e = o.htmlParser.backSpaceHtmlChars(t, e, s)
+ var n = t.substr(0, e)
+ if ((s.replaceText(n), s.smartBackspace)) {
+ var i = s.strings[s.arrayPos + 1]
+ i && n === i.substr(0, e)
+ ? (s.stopNum = e)
+ : (s.stopNum = 0)
+ }
+ e > s.stopNum
+ ? (e--, s.backspace(t, e))
+ : e <= s.stopNum &&
+ (s.arrayPos++,
+ s.arrayPos === s.strings.length
+ ? ((s.arrayPos = 0),
+ s.options.onLastStringBackspaced(),
+ s.shuffleStringsIfNeeded(),
+ s.begin())
+ : s.typewrite(s.strings[s.sequence[s.arrayPos]], e))
+ }, n)
+ }
+ },
+ {
+ key: 'complete',
+ value: function () {
+ this.options.onComplete(this),
+ this.loop ? this.curLoop++ : (this.typingComplete = !0)
+ }
+ },
+ {
+ key: 'setPauseStatus',
+ value: function (t, e, s) {
+ ;(this.pause.typewrite = s),
+ (this.pause.curString = t),
+ (this.pause.curStrPos = e)
+ }
+ },
+ {
+ key: 'toggleBlinking',
+ value: function (t) {
+ this.cursor &&
+ (this.pause.status ||
+ (this.cursorBlinking !== t &&
+ ((this.cursorBlinking = t),
+ t
+ ? this.cursor.classList.add('typed-cursor--blink')
+ : this.cursor.classList.remove(
+ 'typed-cursor--blink'
+ ))))
+ }
+ },
+ {
+ key: 'humanizer',
+ value: function (t) {
+ return Math.round((Math.random() * t) / 2) + t
+ }
+ },
+ {
+ key: 'shuffleStringsIfNeeded',
+ value: function () {
+ this.shuffle &&
+ (this.sequence = this.sequence.sort(function () {
+ return Math.random() - 0.5
+ }))
+ }
+ },
+ {
+ key: 'initFadeOut',
+ value: function () {
+ var t = this
+ return (
+ (this.el.className += ' ' + this.fadeOutClass),
+ this.cursor &&
+ (this.cursor.className += ' ' + this.fadeOutClass),
+ setTimeout(function () {
+ t.arrayPos++,
+ t.replaceText(''),
+ t.strings.length > t.arrayPos
+ ? t.typewrite(t.strings[t.sequence[t.arrayPos]], 0)
+ : (t.typewrite(t.strings[0], 0), (t.arrayPos = 0))
+ }, this.fadeOutDelay)
+ )
+ }
+ },
+ {
+ key: 'replaceText',
+ value: function (t) {
+ this.attr
+ ? this.el.setAttribute(this.attr, t)
+ : this.isInput
+ ? (this.el.value = t)
+ : 'html' === this.contentType
+ ? (this.el.innerHTML = t)
+ : (this.el.textContent = t)
+ }
+ },
+ {
+ key: 'bindFocusEvents',
+ value: function () {
+ var t = this
+ this.isInput &&
+ (this.el.addEventListener('focus', function (e) {
+ t.stop()
+ }),
+ this.el.addEventListener('blur', function (e) {
+ ;(t.el.value && 0 !== t.el.value.length) || t.start()
+ }))
+ }
+ },
+ {
+ key: 'insertCursor',
+ value: function () {
+ this.showCursor &&
+ (this.cursor ||
+ ((this.cursor = document.createElement('span')),
+ (this.cursor.className = 'typed-cursor'),
+ this.cursor.setAttribute('aria-hidden', !0),
+ (this.cursor.innerHTML = this.cursorChar),
+ this.el.parentNode &&
+ this.el.parentNode.insertBefore(
+ this.cursor,
+ this.el.nextSibling
+ )))
+ }
+ }
+ ]),
+ t
+ )
+ })()
+ ;(e['default'] = a), (t.exports = e['default'])
+ },
+ function (t, e, s) {
+ 'use strict'
+ function n(t) {
+ return t && t.__esModule ? t : { default: t }
+ }
+ function i(t, e) {
+ if (!(t instanceof e))
+ throw new TypeError('Cannot call a class as a function')
+ }
+ Object.defineProperty(e, '__esModule', { value: !0 })
+ var r =
+ Object.assign ||
+ function (t) {
+ for (var e = 1; e < arguments.length; e++) {
+ var s = arguments[e]
+ for (var n in s)
+ Object.prototype.hasOwnProperty.call(s, n) && (t[n] = s[n])
+ }
+ return t
+ },
+ o = (function () {
+ function t(t, e) {
+ for (var s = 0; s < e.length; s++) {
+ var n = e[s]
+ ;(n.enumerable = n.enumerable || !1),
+ (n.configurable = !0),
+ 'value' in n && (n.writable = !0),
+ Object.defineProperty(t, n.key, n)
+ }
+ }
+ return function (e, s, n) {
+ return s && t(e.prototype, s), n && t(e, n), e
+ }
+ })(),
+ a = s(2),
+ u = n(a),
+ l = (function () {
+ function t() {
+ i(this, t)
+ }
+ return (
+ o(t, [
+ {
+ key: 'load',
+ value: function (t, e, s) {
+ if (
+ ('string' == typeof s
+ ? (t.el = document.querySelector(s))
+ : (t.el = s),
+ (t.options = r({}, u['default'], e)),
+ (t.isInput = 'input' === t.el.tagName.toLowerCase()),
+ (t.attr = t.options.attr),
+ (t.bindInputFocusEvents = t.options.bindInputFocusEvents),
+ (t.showCursor = !t.isInput && t.options.showCursor),
+ (t.cursorChar = t.options.cursorChar),
+ (t.cursorBlinking = !0),
+ (t.elContent = t.attr
+ ? t.el.getAttribute(t.attr)
+ : t.el.textContent),
+ (t.contentType = t.options.contentType),
+ (t.typeSpeed = t.options.typeSpeed),
+ (t.startDelay = t.options.startDelay),
+ (t.backSpeed = t.options.backSpeed),
+ (t.smartBackspace = t.options.smartBackspace),
+ (t.backDelay = t.options.backDelay),
+ (t.fadeOut = t.options.fadeOut),
+ (t.fadeOutClass = t.options.fadeOutClass),
+ (t.fadeOutDelay = t.options.fadeOutDelay),
+ (t.isPaused = !1),
+ (t.strings = t.options.strings.map(function (t) {
+ return t.trim()
+ })),
+ 'string' == typeof t.options.stringsElement
+ ? (t.stringsElement = document.querySelector(
+ t.options.stringsElement
+ ))
+ : (t.stringsElement = t.options.stringsElement),
+ t.stringsElement)
+ ) {
+ ;(t.strings = []), (t.stringsElement.style.display = 'none')
+ var n = Array.prototype.slice.apply(
+ t.stringsElement.children
+ ),
+ i = n.length
+ if (i)
+ for (var o = 0; o < i; o += 1) {
+ var a = n[o]
+ t.strings.push(a.innerHTML.trim())
+ }
+ }
+ ;(t.strPos = 0),
+ (t.arrayPos = 0),
+ (t.stopNum = 0),
+ (t.loop = t.options.loop),
+ (t.loopCount = t.options.loopCount),
+ (t.curLoop = 0),
+ (t.shuffle = t.options.shuffle),
+ (t.sequence = []),
+ (t.pause = {
+ status: !1,
+ typewrite: !0,
+ curString: '',
+ curStrPos: 0
+ }),
+ (t.typingComplete = !1)
+ for (var o in t.strings) t.sequence[o] = o
+ ;(t.currentElContent = this.getCurrentElContent(t)),
+ (t.autoInsertCss = t.options.autoInsertCss),
+ this.appendAnimationCss(t)
+ }
+ },
+ {
+ key: 'getCurrentElContent',
+ value: function (t) {
+ var e = ''
+ return (e = t.attr
+ ? t.el.getAttribute(t.attr)
+ : t.isInput
+ ? t.el.value
+ : 'html' === t.contentType
+ ? t.el.innerHTML
+ : t.el.textContent)
+ }
+ },
+ {
+ key: 'appendAnimationCss',
+ value: function (t) {
+ var e = 'data-typed-js-css'
+ if (
+ t.autoInsertCss &&
+ (t.showCursor || t.fadeOut) &&
+ !document.querySelector('[' + e + ']')
+ ) {
+ var s = document.createElement('style')
+ ;(s.type = 'text/css'), s.setAttribute(e, !0)
+ var n = ''
+ t.showCursor &&
+ (n +=
+ '\n .typed-cursor{\n opacity: 1;\n }\n .typed-cursor.typed-cursor--blink{\n animation: typedjsBlink 0.7s infinite;\n -webkit-animation: typedjsBlink 0.7s infinite;\n animation: typedjsBlink 0.7s infinite;\n }\n @keyframes typedjsBlink{\n 50% { opacity: 0.0; }\n }\n @-webkit-keyframes typedjsBlink{\n 0% { opacity: 1; }\n 50% { opacity: 0.0; }\n 100% { opacity: 1; }\n }\n '),
+ t.fadeOut &&
+ (n +=
+ '\n .typed-fade-out{\n opacity: 0;\n transition: opacity .25s;\n }\n .typed-cursor.typed-cursor--blink.typed-fade-out{\n -webkit-animation: 0;\n animation: 0;\n }\n '),
+ 0 !== s.length &&
+ ((s.innerHTML = n), document.body.appendChild(s))
+ }
+ }
+ }
+ ]),
+ t
+ )
+ })()
+ e['default'] = l
+ var c = new l()
+ e.initializer = c
+ },
+ function (t, e) {
+ 'use strict'
+ Object.defineProperty(e, '__esModule', { value: !0 })
+ var s = {
+ strings: [
+ 'These are the default values...',
+ 'You know what you should do?',
+ 'Use your own!',
+ 'Have a great day!'
+ ],
+ stringsElement: null,
+ typeSpeed: 0,
+ startDelay: 0,
+ backSpeed: 0,
+ smartBackspace: !0,
+ shuffle: !1,
+ backDelay: 700,
+ fadeOut: !1,
+ fadeOutClass: 'typed-fade-out',
+ fadeOutDelay: 500,
+ loop: !1,
+ loopCount: 1 / 0,
+ showCursor: !0,
+ cursorChar: '|',
+ autoInsertCss: !0,
+ attr: null,
+ bindInputFocusEvents: !1,
+ contentType: 'html',
+ onBegin: function (t) {},
+ onComplete: function (t) {},
+ preStringTyped: function (t, e) {},
+ onStringTyped: function (t, e) {},
+ onLastStringBackspaced: function (t) {},
+ onTypingPaused: function (t, e) {},
+ onTypingResumed: function (t, e) {},
+ onReset: function (t) {},
+ onStop: function (t, e) {},
+ onStart: function (t, e) {},
+ onDestroy: function (t) {}
+ }
+ ;(e['default'] = s), (t.exports = e['default'])
+ },
+ function (t, e) {
+ 'use strict'
+ function s(t, e) {
+ if (!(t instanceof e))
+ throw new TypeError('Cannot call a class as a function')
+ }
+ Object.defineProperty(e, '__esModule', { value: !0 })
+ var n = (function () {
+ function t(t, e) {
+ for (var s = 0; s < e.length; s++) {
+ var n = e[s]
+ ;(n.enumerable = n.enumerable || !1),
+ (n.configurable = !0),
+ 'value' in n && (n.writable = !0),
+ Object.defineProperty(t, n.key, n)
+ }
+ }
+ return function (e, s, n) {
+ return s && t(e.prototype, s), n && t(e, n), e
+ }
+ })(),
+ i = (function () {
+ function t() {
+ s(this, t)
+ }
+ return (
+ n(t, [
+ {
+ key: 'typeHtmlChars',
+ value: function (t, e, s) {
+ if ('html' !== s.contentType) return e
+ var n = t.substr(e).charAt(0)
+ if ('<' === n || '&' === n) {
+ var i = ''
+ for (
+ i = '<' === n ? '>' : ';';
+ t.substr(e + 1).charAt(0) !== i &&
+ (e++, !(e + 1 > t.length));
+
+ );
+ e++
+ }
+ return e
+ }
+ },
+ {
+ key: 'backSpaceHtmlChars',
+ value: function (t, e, s) {
+ if ('html' !== s.contentType) return e
+ var n = t.substr(e).charAt(0)
+ if ('>' === n || ';' === n) {
+ var i = ''
+ for (
+ i = '>' === n ? '<' : '&';
+ t.substr(e - 1).charAt(0) !== i && (e--, !(e < 0));
+
+ );
+ e--
+ }
+ return e
+ }
+ }
+ ]),
+ t
+ )
+ })()
+ e['default'] = i
+ var r = new i()
+ e.htmlParser = r
+ }
+ ])
+})
+//# sourceMappingURL=typed.min.js.map
diff --git a/public/svg/xiaohongshu.svg b/public/svg/xiaohongshu.svg
new file mode 100644
index 00000000..3a5e4222
--- /dev/null
+++ b/public/svg/xiaohongshu.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/svg/zhishixingqiu.svg b/public/svg/zhishixingqiu.svg
new file mode 100644
index 00000000..77293e8f
--- /dev/null
+++ b/public/svg/zhishixingqiu.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/styles/globals.css b/styles/globals.css
index 2b8f568f..bdc13fe9 100644
--- a/styles/globals.css
+++ b/styles/globals.css
@@ -264,3 +264,11 @@ a.avatar-wrapper {
writing-mode: vertical-rl; /* 竖向排列从右向左 */
text-orientation: upright; /* 文字方向正常 */
}
+
+/* Chatbase 在移动端禁止遮挡 */
+@media (max-width: 700px) {
+ button#chatbase-bubble-button {
+ margin-bottom: 42px;
+ margin-right: 20px;
+ }
+}
diff --git a/styles/notion.css b/styles/notion.css
index 0991011e..ba794f88 100644
--- a/styles/notion.css
+++ b/styles/notion.css
@@ -523,8 +523,10 @@ summary > .notion-h {
.notion-page {
/* width: var(--notion-max-width); */
width: 100% !important;
- padding-left: calc(min(12px, 8vw));
- padding-right: calc(min(12px, 8vw));
+ padding-left: 0px !important;
+ padding-right: 0px !important;
+ /* padding-left: calc(min(12px, 8vw)); */
+ /* padding-right: calc(min(12px, 8vw)); */
}
.notion-full-width {
@@ -1449,6 +1451,7 @@ code[class*='language-'] {
.notion-collection-card-property .notion-page-title-text {
border-bottom: 0 none;
+ @apply dark:text-gray-200;
}
.notion-collection-card-property
diff --git a/themes/commerce/components/BlogPostListPage.js b/themes/commerce/components/BlogPostListPage.js
index d762e083..4c3ba5ac 100644
--- a/themes/commerce/components/BlogPostListPage.js
+++ b/themes/commerce/components/BlogPostListPage.js
@@ -14,7 +14,7 @@ import ProductCard from './ProductCard'
*/
const BlogPostListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
const { NOTION_CONFIG } = useGlobal()
- const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
+ const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', null, NOTION_CONFIG)
const totalPage = Math.ceil(postCount / POSTS_PER_PAGE)
const showPagination = postCount >= POSTS_PER_PAGE
if (!posts || posts.length === 0 || page > totalPage) {
diff --git a/themes/commerce/components/BlogPostListScroll.js b/themes/commerce/components/BlogPostListScroll.js
index 004e2b5e..a00b8cc3 100644
--- a/themes/commerce/components/BlogPostListScroll.js
+++ b/themes/commerce/components/BlogPostListScroll.js
@@ -20,7 +20,7 @@ const BlogPostListScroll = ({
siteInfo
}) => {
const { NOTION_CONFIG } = useGlobal()
- const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
+ const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', null, NOTION_CONFIG)
const [page, updatePage] = useState(1)
const postsToShow = getListByPage(posts, page, POSTS_PER_PAGE)
diff --git a/themes/commerce/components/SocialButton.js b/themes/commerce/components/SocialButton.js
index 555e8ea6..24823924 100644
--- a/themes/commerce/components/SocialButton.js
+++ b/themes/commerce/components/SocialButton.js
@@ -5,39 +5,101 @@ import { siteConfig } from '@/lib/config'
* @constructor
*/
const SocialButton = () => {
- return
-
- {siteConfig('CONTACT_GITHUB') &&
-
- }
- {siteConfig('CONTACT_TWITTER') &&
-
- }
- {siteConfig('CONTACT_TELEGRAM') &&
-
- }
- {siteConfig('CONTACT_LINKEDIN') &&
-
- }
- {siteConfig('CONTACT_WEIBO') &&
-
- }
- {siteConfig('CONTACT_INSTAGRAM') &&
-
- }
- {siteConfig('CONTACT_EMAIL') &&
-
- }
- {JSON.parse(siteConfig('ENABLE_RSS')) &&
-
- }
- {siteConfig('CONTACT_BILIBILI') &&
-
- }
- {siteConfig('CONTACT_YOUTUBE') &&
-
- }
+ return (
+
+
+ {siteConfig('CONTACT_GITHUB') && (
+
+
+
+ )}
+ {siteConfig('CONTACT_TWITTER') && (
+
+
+
+ )}
+ {siteConfig('CONTACT_TELEGRAM') && (
+
+
+
+ )}
+ {siteConfig('CONTACT_LINKEDIN') && (
+
+
+
+ )}
+ {siteConfig('CONTACT_WEIBO') && (
+
+
+
+ )}
+ {siteConfig('CONTACT_INSTAGRAM') && (
+
+
+
+ )}
+ {siteConfig('CONTACT_EMAIL') && (
+
+
+
+ )}
+ {JSON.parse(siteConfig('ENABLE_RSS')) && (
+
+
+
+ )}
+ {siteConfig('CONTACT_BILIBILI') && (
+
+
+
+ )}
+ {siteConfig('CONTACT_YOUTUBE') && (
+
+
+
+ )}
+
-
+ )
}
export default SocialButton
diff --git a/themes/example/components/BlogListPage.js b/themes/example/components/BlogListPage.js
index f9ae29a4..fe56e0bf 100644
--- a/themes/example/components/BlogListPage.js
+++ b/themes/example/components/BlogListPage.js
@@ -14,7 +14,7 @@ export const BlogListPage = props => {
const { locale, NOTION_CONFIG } = useGlobal()
const router = useRouter()
const totalPage = Math.ceil(
- postCount / siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
+ postCount / siteConfig('POSTS_PER_PAGE', null, NOTION_CONFIG)
)
const currentPage = +page
@@ -24,6 +24,7 @@ export const BlogListPage = props => {
.split('?')[0]
.replace(/\/page\/[1-9]\d*/, '')
.replace(/\/$/, '')
+ .replace('.html', '')
const showPageCover = siteConfig('EXAMPLE_POST_LIST_COVER', null, CONFIG)
@@ -44,7 +45,7 @@ export const BlogListPage = props => {
: `${pagePrefix}/page/${currentPage - 1}`,
query: router.query.s ? { s: router.query.s } : {}
}}
- className={`${showPrev ? 'bg-black ' : 'bg-gray pointer-events-none '} text-white no-underline py-2 px-3 rounded`}>
+ className={`${showPrev ? 'bg-black dark:bg-hexo-black-gray' : 'bg-gray pointer-events-none invisible'} text-white no-underline py-2 px-3 rounded`}>
{locale.PAGINATION.PREV}
{
pathname: `${pagePrefix}/page/${currentPage + 1}`,
query: router.query.s ? { s: router.query.s } : {}
}}
- className={`${showNext ? 'bg-black ' : 'bg-gray pointer-events-none '} text-white no-underline py-2 px-3 rounded`}>
+ className={`${showNext ? 'bg-black dark:bg-hexo-black-gray ' : 'bg-gray pointer-events-none invisible'} text-white no-underline py-2 px-3 rounded`}>
{locale.PAGINATION.NEXT}
diff --git a/themes/example/components/BlogListScroll.js b/themes/example/components/BlogListScroll.js
index 3ddc340a..d712b919 100644
--- a/themes/example/components/BlogListScroll.js
+++ b/themes/example/components/BlogListScroll.js
@@ -13,7 +13,7 @@ export const BlogListScroll = props => {
const { posts } = props
const { locale, NOTION_CONFIG } = useGlobal()
const [page, updatePage] = useState(1)
- const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
+ const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', null, NOTION_CONFIG)
let hasMore = false
const postsToShow = posts
diff --git a/themes/example/components/Catalog.js b/themes/example/components/Catalog.js
new file mode 100644
index 00000000..161a6cae
--- /dev/null
+++ b/themes/example/components/Catalog.js
@@ -0,0 +1,94 @@
+import throttle from 'lodash.throttle'
+import { uuidToId } from 'notion-utils'
+import { useCallback, useEffect, useRef, useState } from 'react'
+
+/**
+ * 目录导航组件
+ * @param toc
+ * @returns {JSX.Element}
+ * @constructor
+ */
+const Catalog = ({ toc }) => {
+ // 监听滚动事件
+ useEffect(() => {
+ window.addEventListener('scroll', actionSectionScrollSpy)
+ actionSectionScrollSpy()
+ return () => {
+ window.removeEventListener('scroll', actionSectionScrollSpy)
+ }
+ }, [])
+
+ // 目录自动滚动
+ const tRef = useRef(null)
+ const tocIds = []
+
+ // 同步选中目录事件
+ const [activeSection, setActiveSection] = useState(null)
+ const throttleMs = 200
+ const actionSectionScrollSpy = useCallback(
+ throttle(() => {
+ const sections = document.getElementsByClassName('notion-h')
+ let prevBBox = null
+ let currentSectionId = activeSection
+ for (let i = 0; i < sections.length; ++i) {
+ const section = sections[i]
+ if (!section || !(section instanceof Element)) continue
+ if (!currentSectionId) {
+ currentSectionId = section.getAttribute('data-id')
+ }
+ const bbox = section.getBoundingClientRect()
+ const prevHeight = prevBBox ? bbox.top - prevBBox.bottom : 0
+ const offset = Math.max(150, prevHeight / 4)
+ // GetBoundingClientRect returns values relative to viewport
+ if (bbox.top - offset < 0) {
+ currentSectionId = section.getAttribute('data-id')
+ prevBBox = bbox
+ continue
+ }
+ // No need to continue loop, if last element has been detected
+ break
+ }
+ setActiveSection(currentSectionId)
+ const index = tocIds.indexOf(currentSectionId) || 0
+ tRef?.current?.scrollTo({ top: 28 * index, behavior: 'smooth' })
+ }, throttleMs)
+ )
+
+ // 无目录就直接返回空
+ if (!toc || toc.length < 1) {
+ return <>>
+ }
+
+ return (
+
+
+
+
+
+ )
+}
+
+export default Catalog
diff --git a/themes/example/components/Header.js b/themes/example/components/Header.js
index 5331eed2..ca60bf63 100644
--- a/themes/example/components/Header.js
+++ b/themes/example/components/Header.js
@@ -4,12 +4,13 @@ import { MenuList } from './MenuList'
/**
* 网站顶部
+ * LOGO 和 菜单
* @returns
*/
export const Header = props => {
return (
-
+
diff --git a/themes/example/components/MenuList.js b/themes/example/components/MenuList.js
index 90b00c7e..ef0c122a 100644
--- a/themes/example/components/MenuList.js
+++ b/themes/example/components/MenuList.js
@@ -58,7 +58,7 @@ export const MenuList = props => {
return (