Merge branch 'main' of https://github.com/tangly1024/NotionNext into feature/user-auth-clerk

This commit is contained in:
tangly1024.com
2024-09-06 16:50:57 +08:00
78 changed files with 3874 additions and 1094 deletions

View File

@@ -1,5 +1,5 @@
# 环境变量 @see https://www.nextjs.cn/docs/basic-features/environment-variables
NEXT_PUBLIC_VERSION=4.6.1
NEXT_PUBLIC_VERSION=4.7.0
# 可在此添加环境变量,去掉最左边的(# )注释即可

View File

@@ -28,16 +28,16 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v3
# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@v1
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -47,14 +47,14 @@ jobs:
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@v3
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
- name: Build and push Docker image
uses: docker/build-push-action@v2
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64

View File

@@ -24,11 +24,11 @@ jobs:
runs-on: ubuntu-latest # 运行环境为最新版的Ubuntu
steps:
- name: 'Checkout codes' # 步骤一,获取仓库代码
uses: actions/checkout@v2
uses: actions/checkout@v4
# - name: 'Run baiduPush' # 步骤二执行sh命令文件
# run: npm install && npm run baiduPush # 运行目录是仓库根目录
- name: Set up Python 3.8
uses: actions/setup-python@v1
uses: actions/setup-python@v5
with:
python-version: 3.8

View File

@@ -17,7 +17,7 @@ jobs:
steps:
# Step 1: run a standard checkout action
- name: Checkout target repo
uses: actions/checkout@v3
uses: actions/checkout@v4
# Step 2: run the sync action
- name: Sync upstream changes

2
.gitignore vendored
View File

@@ -45,7 +45,7 @@ yarn-error.log*
/public/robots.txt
/public/sitemap.xml
/public/rss/*
/sitemap.xml
# yarn
package-lock.json

View File

@@ -1,4 +1,6 @@
ARG NOTION_PAGE_ID
ARG NEXT_PUBLIC_THEME
# Install dependencies only when needed
FROM node:18-alpine3.18 AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.

View File

@@ -1,3 +1,13 @@
# 帮助教程
访问帮助:[NotionNext帮助手册](https://docs.tangly1024.com/)
> 本项目教程为免费、公开资源,仅限个人学习使用。严禁任何个人或组织将本教程用于商业用途,包括但不限于直接售卖、间接收费、或其他变相盈利行为。转载、复制或介绍本教程内容时,须保留作者信息并明确注明来源。
> 本项目仅提供由作者团队授权的付费咨询服务,请注意辨别,谨防诈骗行为。任何未经授权的收费服务均可能存在法律风险。
Notion是一个能让效率暴涨的生产力引擎可以帮你书写文档、管理笔记搭建知识库甚至可以为你规划项目、时间管理、组织团队、提高生产力、还有当前最强大的AI技术加持。
> 如果希望进一步探索Notion的功能欢迎购买《[Notion笔记从入门到精通进阶课程](https://docs.tangly1024.com/article/notion-tutorial)》
# NotionNext
<p>
@@ -31,20 +41,6 @@
|--|--|--|--|
| <img src='./docs/theme-next.png' width='300'/> [预览NEXT](https://preview.tangly1024.com/?theme=next) | <img src='./docs/theme-medium.png' width='300'/> [预览MEDIUM](https://preview.tangly1024.com/?theme=medium) | <img src='./docs/theme-hexo.png' width='300'/> [预览HEXO](https://preview.tangly1024.com/?theme=hexo) | <img src='./docs/theme-fukasawa.png' width='300'/> [预览FUKASAWA](https://preview.tangly1024.com/?theme=fukasawa) |
## 我要如何开始?
只需几分钟即可搭建您的个人站点:
- [部署教程 (支持多方案)](https://docs.tangly1024.com/)
- [配置手册 - (自定义插件)](https://docs.tangly1024.com/article/notion-next-guide)
- [二次开发 - (开发手册)](https://docs.tangly1024.com/article/notion-next-secondary-menu)
- [更新指南 - (升级您的代码)](https://docs.tangly1024.com/article/how-to-update-notionnext)
- [版本汇总 - (查询变动功能)](https://docs.tangly1024.com/article/notion-next-changelogs)
## 致谢
感谢Craig Hart发起的Nobelium项目

View File

@@ -1,3 +1,15 @@
# Free Installation and Usage Guide
Click here to access the help documentation: NotionNext Help Manual - (Completely Free)
## Rights Statement
This project's tutorial is a free and open resource intended solely for personal learning use. It is strictly prohibited for any individual or organization to use this tutorial for commercial purposes, including but not limited to direct sales, indirect charges, or any other forms of profit. When reproducing, copying, or sharing this tutorial, the author's information must be retained, and the source clearly cited.
This project only offers paid consultation services authorized by the author's team. Please be vigilant against fraud. Any unauthorized paid services may be subject to legal risks.
You can set up your personal website in just a few minutes. Here is the link to my free tutorial:
# NotionNext
<p>
@@ -31,20 +43,6 @@ Live Demo[https://preview.tangly1024.com/](https://preview.tangly1024.com/)
|--|--|--|--|
| <img src='./docs/theme-next.png' width='300'/> [NEXT](https://preview.tangly1024.com/?theme=next) | <img src='./docs/theme-medium.png' width='300'/> [MEDIUM](https://preview.tangly1024.com/?theme=medium) | <img src='./docs/theme-hexo.png' width='300'/> [HEXO](https://preview.tangly1024.com/?theme=hexo) | <img src='./docs/theme-fukasawa.png' width='300'/> [FUKASAWA](https://preview.tangly1024.com/?theme=fukasawa) |
## Get Start!
It only takes a few minutes to set up your personal site:
- [Quick Deployment Tutorial - Multiple Options Available](https://docs.tangly1024.com/article/vercel-deploy-notion-next)
- [Customization Guide - How to Configure Feature Plugins](https://docs.tangly1024.com/article/how-to-config-notion-next)
- [Development Guide - How to Conduct Local Development](https://docs.tangly1024.com/article/how-to-develop-with-notion-next)
- [Update Guide - How to Get the Latest Upgrade Patch](https://docs.tangly1024.com/article/how-to-update-notionnext)
- [Version History - Check Feature Highlights for Each Version](https://docs.tangly1024.com/article/latest)
## Acknowledgements
Special thanks to Craig Hart for initiating the Nobelium project.

View File

@@ -546,7 +546,7 @@ const BLOG = {
process.env.ENABLE_CACHE ||
process.env.npm_lifecycle_event === 'build' ||
process.env.npm_lifecycle_event === 'export', // 在打包过程中默认开启缓存,开发或运行时开启此功能意义不大。
isProd: process.env.VERCEL_ENV === 'production' || process.env.EXPORT, // distinguish between development and production environment (ref: https://vercel.com/docs/environment-variables#system-environment-variables) isProd: process.env.VERCEL_ENV === 'production' // distinguish between development and production environment (ref: https://vercel.com/docs/environment-variables#system-environment-variables)
isProd: process.env.VERCEL_ENV === 'production' || process.env.EXPORT, // distinguish between development and production environment (ref: https://vercel.com/docs/environment-variables#system-environment-variables)
BUNDLE_ANALYZER: process.env.ANALYZE === 'true' || false, // 是否展示编译依赖内容与大小
VERSION: process.env.NEXT_PUBLIC_VERSION // 版本号
}

View File

@@ -10,14 +10,8 @@ import { useEffect } from 'react'
export default function AOSAnimation() {
const initAOS = async () => {
Promise.all([
loadExternalResource(
'https://cdn.bootcdn.net/ajax/libs/aos/2.3.4/aos.js',
'js'
),
loadExternalResource(
'https://cdn.bootcdn.net/ajax/libs/aos/2.3.4/aos.css',
'css'
)
loadExternalResource('/js/aos.js', 'js'),
loadExternalResource('/css/aos.css', 'css')
]).then(() => {
if (window.AOS) {
window.AOS.init()

View File

@@ -24,19 +24,19 @@ const Ackee = () => {
},
{
/*
* Enable or disable tracking of personal data.
* We recommend to ask the user for permission before turning this option on.
*/
* Enable or disable tracking of personal data.
* We recommend to ask the user for permission before turning this option on.
*/
detailed: true,
/*
* Enable or disable tracking when on localhost.
*/
* Enable or disable tracking when on localhost.
*/
ignoreLocalhost: false,
/*
* Enable or disable the tracking of your own visits.
* This is enabled by default, but should be turned off when using a wildcard Access-Control-Allow-Origin header.
* Some browsers strictly block third-party cookies. The option won't have an impact when this is the case.
*/
* Enable or disable the tracking of your own visits.
* This is enabled by default, but should be turned off when using a wildcard Access-Control-Allow-Origin header.
* Some browsers strictly block third-party cookies. The option won't have an impact when this is the case.
*/
ignoreOwnVisits: false
}
)

View File

@@ -117,12 +117,14 @@ export default function CustomContextMenu(props) {
function handleCopy() {
const selectedText = document.getSelection().toString()
if (selectedText) {
const tempInput = document.createElement('input')
tempInput.value = selectedText
document.body.appendChild(tempInput)
tempInput.select()
document.execCommand('copy')
document.body.removeChild(tempInput)
const tempInput = document.createElement('input');
tempInput.value = selectedText;
document.body.appendChild(tempInput);
tempInput.select();
document.execCommand('copy');
if (tempInput && tempInput.parentNode && tempInput.parentNode.contains(tempInput)) {
tempInput.parentNode.removeChild(tempInput);
}
// alert("Text copied: " + selectedText);
} else {
// alert("Please select some text first.");

View File

@@ -24,7 +24,9 @@ export default function DifyChatbot() {
return () => {
// 在组件卸载时清理 script 标签
const existingScript = document.getElementById(siteConfig('DIFY_CHATBOT_TOKEN')); // 注意调用 siteConfig()
if (existingScript) document.body.removeChild(existingScript);
if (existingScript && existingScript.parentNode && existingScript.parentNode.contains(existingScript)) {
existingScript.parentNode.removeChild(existingScript);
}
};
}, []); // 注意依赖数组为空,意味着脚本将仅在加载页面时执行一次

View File

@@ -63,6 +63,7 @@ const ExternalPlugin = props => {
const MOUSE_FOLLOW = siteConfig('MOUSE_FOLLOW')
const CUSTOM_EXTERNAL_CSS = siteConfig('CUSTOM_EXTERNAL_CSS')
const CUSTOM_EXTERNAL_JS = siteConfig('CUSTOM_EXTERNAL_JS')
const ENABLE_NPROGRSS = siteConfig('ENABLE_NPROGRSS', true)
// 自定义样式css和js引入
if (isBrowser) {
@@ -145,7 +146,7 @@ const ExternalPlugin = props => {
{AD_WWADS_BLOCK_DETECT && <AdBlockDetect />}
{TIANLI_KEY && <TianLiGPT />}
<VConsole />
<LoadingProgress />
{ENABLE_NPROGRSS && <LoadingProgress />}
<AosAnimation />
{ANALYTICS_51LA_ID && ANALYTICS_51LA_CK && <LA51 />}
@@ -186,10 +187,19 @@ const ExternalPlugin = props => {
async
dangerouslySetInnerHTML={{
__html: `
(function(c,l,a,r,i,t,y){
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
(function(c, l, a, r, i, t, y) {
c[a] = c[a] || function() {
(c[a].q = c[a].q || []).push(arguments);
};
t = l.createElement(r);
t.async = 1;
t.src = "https://www.clarity.ms/tag/" + i;
y = l.getElementsByTagName(r)[0];
if (y && y.parentNode) {
y.parentNode.insertBefore(t, y);
} else {
l.head.appendChild(t);
}
})(window, document, "clarity", "script", "${CLARITY_ID}");
`
}}
@@ -204,8 +214,24 @@ const ExternalPlugin = props => {
async
dangerouslySetInnerHTML={{
__html: `
(function(i,s,o,g,r,a,m){i["DaoVoiceObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;a.charset="utf-8";m.parentNode.insertBefore(a,m)})(window,document,"script",('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/daf1a94b.js","daovoice")
`
(function(i, s, o, g, r, a, m) {
i["DaoVoiceObject"] = r;
i[r] = i[r] || function() {
(i[r].q = i[r].q || []).push(arguments);
};
i[r].l = 1 * new Date();
a = s.createElement(o);
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
a.charset = "utf-8";
if (m && m.parentNode) {
m.parentNode.insertBefore(a, m);
} else {
s.head.appendChild(a);
}
})(window, document, "script", ('https:' == document.location.protocol ? 'https:' : 'http:') + "//widget.daovoice.io/widget/daf1a94b.js", "daovoice")
`
}}
/>
<script

View File

@@ -116,7 +116,11 @@ class MessengerCustomerChat extends Component {
js = d.createElement(s);
js.id = id;
js.src = `https://connect.facebook.net/${language}/sdk/xfbml.customerchat.js`;
fjs.parentNode.insertBefore(js, fjs);
if (fjs && fjs.parentNode && fjs.parentNode.contains(fjs)) {
fjs.parentNode.insertBefore(js, fjs);
} else {
document.body.appendChild(js);
}
})(document, 'script', 'facebook-jssdk');
/* eslint-enable */
}

View File

@@ -18,7 +18,7 @@ const Fireworks = () => {
// 异步加载
async function loadFireworks() {
loadExternalResource(
'https://cdn.bootcdn.net/ajax/libs/animejs/3.2.1/anime.min.js',
'https://cdnjs.snrat.com/ajax/libs/animejs/3.2.1/anime.min.js',
'js'
).then(() => {
loadExternalResource('/js/fireworks.js', 'js').then(() => {

View File

@@ -0,0 +1,71 @@
import { useGlobal } from '@/lib/global'
import { useEffect, useState } from 'react'
/**
* @see https://css-loaders.com/
* @returns 加载动画
*/
export default function LoadingCover() {
const { onLoading, setOnLoading } = useGlobal()
const [isVisible, setIsVisible] = useState(false) // 初始状态设置为false避免服务端渲染与客户端渲染不一致
useEffect(() => {
// 确保在客户端渲染时才设置可见性
if (onLoading) {
setIsVisible(true)
} else {
const timeout = setTimeout(() => setIsVisible(false), 1500) // 等待淡出动画结束
return () => clearTimeout(timeout)
}
}, [onLoading])
const handleClick = () => {
setOnLoading(false) // 强行关闭 LoadingCover
}
if (typeof window === 'undefined') {
return null // 避免在服务端渲染时渲染出这个组件
}
return isVisible ? (
<div
id='loading-cover'
onClick={handleClick}
className={`dark:text-white text-black bg-white dark:bg-black animate__animated animate__faster ${
onLoading ? 'animate__fadeIn' : 'animate__fadeOut'
} flex flex-col justify-center z-50 w-full h-screen fixed top-0 left-0`}>
<div className='mx-auto'>
<style global>
{`
.loader {
width: 20px;
aspect-ratio: 1;
border-radius: 50%;
background: #000;
box-shadow: 0 0 0 0 #0004;
animation: l2 1.5s infinite linear;
position: relative;
}
.loader:before,
.loader:after {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
box-shadow: 0 0 0 0 #0004;
animation: inherit;
animation-delay: -0.5s;
}
.loader:after {
animation-delay: -1s;
}
@keyframes l2 {
100% {
box-shadow: 0 0 0 40px #0000;
}
}`}
</style>
<div className='loader'></div>
</div>
</div>
) : null
}

View File

@@ -3,7 +3,8 @@ import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
/**
* 出现页面加载进度条
* 加载进度条
* NProgress实现
*/
export default function LoadingProgress() {
const router = useRouter()
@@ -11,7 +12,7 @@ export default function LoadingProgress() {
// 加载进度条
useEffect(() => {
loadExternalResource(
'https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.js',
'https://cdnjs.snrat.com/ajax/libs/nprogress/0.2.0/nprogress.min.js',
'js'
).then(() => {
if (window.NProgress) {
@@ -19,7 +20,7 @@ export default function LoadingProgress() {
// 调速
window.NProgress.settings.minimun = 0.1
loadExternalResource(
'https://cdn.bootcdn.net/ajax/libs/nprogress/0.2.0/nprogress.min.css',
'https://cdnjs.snrat.com/ajax/libs/nprogress/0.2.0/nprogress.min.css',
'css'
)
}

140
components/OpenWrite.js Normal file
View File

@@ -0,0 +1,140 @@
import { siteConfig } from '@/lib/config'
import { isBrowser, loadExternalResource } from '@/lib/utils'
import { useRouter } from 'next/router'
import { useEffect } from 'react'
/**
* OpenWrite公众号导流插件
* 使用介绍https://openwrite.cn/guide/readmore/readmore.html#%E4%BA%8C%E3%80%81%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8
* 登录后台配置你的博客https://readmore.openwrite.cn/
* @returns
*/
const OpenWrite = () => {
const router = useRouter()
const qrcode = siteConfig('OPEN_WRITE_QRCODE', '请配置公众号二维码')
const blogId = siteConfig('OPEN_WRITE_BLOG_ID')
const name = siteConfig('OPEN_WRITE_NAME', '请配置公众号名')
const id = 'article-wrapper'
const keyword = siteConfig('OPEN_WRITE_KEYWORD', '请配置公众号关键词')
const btnText = siteConfig(
'OPEN_WRITE_BTN_TEXT',
'原创不易,完成人机检测,阅读全文'
)
// 验证一次后的有效时长,单位小时
const cookieAge = siteConfig('OPEN_WRITE_VALIDITY_DURATION', 1)
// 白名单
const whiteList = siteConfig('OPEN_WRITE_WHITE_LIST', '')
const loadOpenWrite = async () => {
const existWhite = existedWhiteList(router.asPath, whiteList)
// 如果当前页面在白名单中,则屏蔽加锁
if (existWhite) {
return
}
try {
await loadExternalResource(
'https://readmore.openwrite.cn/js/readmore-2.0.js',
'js'
)
const BTWPlugin = window?.BTWPlugin
if (BTWPlugin) {
const btw = new BTWPlugin()
window.btw = btw
btw.init({
qrcode,
id,
name,
btnText,
keyword,
blogId,
cookieAge
})
// btw初始化后开始监听read-more-wrap何时消失
const intervalId = setInterval(() => {
const readMoreWrapElement = document.getElementById('read-more-wrap')
const articleWrapElement = document.getElementById('article-wrapper')
if (!readMoreWrapElement && articleWrapElement) {
toggleTocItems(false) // 恢复目录项的点击
// 自动调整文章区域的高度
articleWrapElement.style.height = 'auto'
// 停止定时器
clearInterval(intervalId)
}
}, 1000) // 每秒检查一次
// Return cleanup function to clear the interval if the component unmounts
return () => clearInterval(intervalId)
}
} catch (error) {
console.error('OpenWrite 加载异常', error)
}
}
useEffect(() => {
if (isBrowser && blogId) {
// Check if the element with id 'read-more-wrap' already exists
const readMoreWrap = document.getElementById('read-more-wrap')
// Only load the script if the element doesn't exist
if (!readMoreWrap) {
loadOpenWrite()
toggleTocItems(true) // 禁止目录项的点击
}
}
})
// 启动一个监听器,当页面上存在#read-more-wrap对象时所有的 a .notion-table-of-contents-item 对象都禁止点击
return <></>
}
// 定义禁用和恢复目录项点击的函数
const toggleTocItems = disable => {
const tocItems = document.querySelectorAll('a.notion-table-of-contents-item')
tocItems.forEach(item => {
if (disable) {
item.style.pointerEvents = 'none'
item.style.opacity = '0.5'
} else {
item.style.pointerEvents = 'auto'
item.style.opacity = '1'
}
})
}
/**
* 检查白名单
* @param {*} path 当前url的字符串
* @param {*} whiteListStr 白名单字符串
*/
function existedWhiteList(path, whiteListStr) {
// 参数检查
if (!path || !whiteListStr) {
return true
}
// 提取 path 最后一个斜杠后的内容,去掉前面的斜杆
// 移除查询参数(从 '?' 开始的部分)和 `.html` 后缀
const processedPath = path
.replace(/\?.*$/, '') // 移除查询参数
.replace(/.*\/([^/]+)(?:\.html)?$/, '$1') // 去掉前面的路径和 .html
// 严格检查白名单字符串中是否包含处理后的 path
// const whiteListArray = whiteListStr.split(',')
// return whiteListArray.includes(processedPath)
// 放宽判断
const isWhite = whiteListStr.includes(processedPath)
if (isWhite) {
console.log('OpenWrite白名单', processedPath)
}
return isWhite
}
export default OpenWrite

View File

@@ -34,7 +34,7 @@ export function PWA(post, siteInfo) {
// 删除已有的 manifest link 元素(如果存在)
const existingManifest = document.querySelector('link[rel="manifest"]')
if (existingManifest) {
if (existingManifest && existingManifest.parentNode && existingManifest.parentNode.contains(existingManifest)) {
existingManifest.parentNode.removeChild(existingManifest)
}

View File

@@ -74,7 +74,7 @@ const loadPrismThemeCSS = (isDarkMode, prismThemeSwitch, prismThemeDarkPath, pri
PRISM_PREVIOUS = prismThemeDarkPath
}
const previousTheme = document.querySelector(`link[href="${PRISM_PREVIOUS}"]`)
if (previousTheme) {
if (previousTheme && previousTheme.parentNode && previousTheme.parentNode.contains(previousTheme)) {
previousTheme.parentNode.removeChild(previousTheme)
}
loadExternalResource(PRISM_THEME, 'css')

View File

@@ -6,8 +6,8 @@ import { useEffect } from 'react';
*/
const useAdjustStyle = () => {
/**
* 避免 callout 含有图片时溢出撑开父容器
*/
* 避免 callout 含有图片时溢出撑开父容器
*/
const adjustCalloutImg = () => {
const callOuts = document.querySelectorAll('.notion-callout-text');
callOuts.forEach((callout) => {

View File

@@ -15,12 +15,6 @@ import {
} from './lang'
const GlobalContext = createContext()
/**
* 定义全局变量,包括语言、主题、深色模式、加载状态
* @param children
* @returns {JSX.Element}
* @constructor
*/
export function GlobalContextProvider(props) {
const {
post,
@@ -40,7 +34,7 @@ export function GlobalContextProvider(props) {
const defaultDarkMode = NOTION_CONFIG?.APPEARANCE || APPEARANCE
const [isDarkMode, updateDarkMode] = useState(defaultDarkMode === 'dark') // 默认深色模式
const [onLoading, setOnLoading] = useState(false) // 抓取文章数据
const [onLoading, setOnLoading] = useState(true) // 抓取文章数据
const router = useRouter()
// 是否全屏
@@ -74,10 +68,6 @@ export function GlobalContextProvider(props) {
htmlElement.classList?.add(newStatus ? 'dark' : 'light')
}
/**
* 更新语言
* 这里是代码级别的多语言,整个站点和文章内容的多语言不在此处理
*/
function changeLang(lang) {
if (lang) {
saveLangToLocalStorage(lang)
@@ -89,13 +79,12 @@ export function GlobalContextProvider(props) {
useEffect(() => {
initDarkMode(updateDarkMode, defaultDarkMode)
initLocale(lang, locale, updateLang, updateLocale)
// 可以
if (NOTION_CONFIG?.REDIRECT_LANG) {
redirectUserLang(NOTION_PAGE_ID)
}
setOnLoading(false)
}, [])
// 加载进度条
useEffect(() => {
const handleStart = url => {
const { theme } = router.query
@@ -103,10 +92,15 @@ export function GlobalContextProvider(props) {
const newUrl = `${url}${url.includes('?') ? '&' : '?'}theme=${theme}`
router.push(newUrl)
}
setOnLoading(true)
if (!onLoading) {
setOnLoading(true)
}
}
const handleStop = () => {
setOnLoading(false)
if (onLoading) {
setOnLoading(false)
}
}
const currentTheme = router?.query?.theme || theme
@@ -120,7 +114,7 @@ export function GlobalContextProvider(props) {
router.events.off('routeChangeComplete', handleStop)
router.events.off('routeChangeError', handleStop)
}
}, [router])
}, [router, onLoading])
return (
<GlobalContext.Provider

View File

@@ -1,3 +1,4 @@
import BLOG from '@/blog.config'
import { getQueryVariable, isBrowser, mergeDeep } from '@/lib/utils'
import enUS from './lang/en-US'
import frFR from './lang/fr-FR'
@@ -127,6 +128,10 @@ export const redirectUserLang = (lang, pageId) => {
if (!window.location.pathname === '/') {
return
}
// 没有开启多语言
if (BLOG.NOTION_PAGE_ID.indexOf(',') < 0) {
return
}
const userLang =
getQueryVariable('locale') ||

View File

@@ -22,6 +22,7 @@ export default {
COMMON: {
THEME: 'Theme',
ARTICLE_LIST: 'Article List',
RECOMMEND_POSTS: 'Recommend Posts',
MORE: 'More',
NO_MORE: 'No More',
LATEST_POSTS: 'Latest posts',

View File

@@ -22,6 +22,7 @@ export default {
COMMON: {
THEME: 'Theme',
ARTICLE_LIST: '文章列表',
RECOMMEND_POSTS: '推荐文章',
MORE: '更多',
NO_MORE: '没有更多了',
LATEST_POSTS: '最新发布',

View File

@@ -81,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) {

View File

@@ -43,7 +43,10 @@ bszCaller = {
return function (t) {
ready(function () {
try {
e(t), scriptTag && scriptTag.parentElement && scriptTag.parentElement.removeChild && scriptTag.parentElement.removeChild(scriptTag)
e(t)
if (scriptTag && scriptTag.parentElement && scriptTag.parentElement.contains(scriptTag)) {
scriptTag.parentElement.removeChild(scriptTag)
}
} catch (t) {
// console.log(t), bszTag.hides()
}

View File

@@ -146,7 +146,7 @@ export function getLastPartOfUrl(url) {
* @param type js 或 css
* @returns {Promise<unknown>}
*/
export function loadExternalResource(url, type) {
export function loadExternalResource(url, type = 'js') {
// 检查是否已存在
const elements =
type === 'js'

View File

@@ -15,7 +15,7 @@ const themes = scanSubdirectories(path.resolve(__dirname, 'themes'))
const locales = (function () {
// 根据BLOG_NOTION_PAGE_ID 检查支持多少种语言数据.
// 支持如下格式配置多个语言的页面id xxx,zh:xxx,en:xxx
const langs = ['zh', 'en']
let langs = [BLOG.LANG.slice(0, 2)]
if (BLOG.NOTION_PAGE_ID.indexOf(',') > 0) {
const siteIds = BLOG.NOTION_PAGE_ID.split(',')
for (let index = 0; index < siteIds.length; index++) {
@@ -33,14 +33,26 @@ const locales = (function () {
})()
// 编译前执行
// 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')
// }
// })()
const preBuild = (function () {
if (
!process.env.npm_lifecycle_event === 'export' &&
!process.env.npm_lifecycle_event === 'build'
) {
return
}
// 删除 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')
}
const sitemap2Path = path.resolve(__dirname, 'sitemap.xml')
if (fs.existsSync(sitemap2Path)) {
fs.unlinkSync(sitemap2Path)
console.log('Deleted existing sitemap.xml from root directory')
}
})()
/**
* 扫描指定目录下的文件夹名,用于获取所有主题
@@ -188,6 +200,10 @@ const nextConfig = {
'themes',
THEME
)
// Enable source maps in development mode
if (process.env.NODE_ENV_API === 'development') {
config.devtool = 'source-map'
}
return config
},
experimental: {
@@ -204,7 +220,6 @@ const nextConfig = {
},
publicRuntimeConfig: {
// 这里的配置既可以服务端获取到,也可以在浏览器端获取到
NODE_ENV_API: process.env.NODE_ENV_API || 'prod',
THEMES: themes
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "notion-next",
"version": "4.6.1",
"version": "4.7.0",
"homepage": "https://github.com/tangly1024/NotionNext.git",
"license": "MIT",
"repository": {

View File

@@ -1,5 +1,6 @@
import BLOG from '@/blog.config'
import useNotification from '@/components/Notification'
import OpenWrite from '@/components/OpenWrite'
import { siteConfig } from '@/lib/config'
import { getGlobalData, getPost, getPostBlocks } from '@/lib/db/getSiteData'
import { useGlobal } from '@/lib/global'
@@ -95,8 +96,12 @@ const Slug = props => {
})
return (
<>
{/* 文章布局 */}
<Layout {...props} />
{/* 解锁密码提示框 */}
{post?.password && post?.password !== '' && !lock && <Notification />}
{/* 导流工具 */}
<OpenWrite />
</>
)
}

View File

@@ -3,6 +3,7 @@ import { siteConfig } from '@/lib/config'
import { getGlobalData, getPostBlocks } from '@/lib/db/getSiteData'
import { generateRobotsTxt } from '@/lib/robots.txt'
import { generateRss } from '@/lib/rss'
import { generateSitemapXml } from '@/lib/sitemap.xml'
import { getLayoutByTheme } from '@/themes/theme'
import { useRouter } from 'next/router'
@@ -62,6 +63,8 @@ export async function getStaticProps(req) {
generateRobotsTxt(props)
// 生成Feed订阅
generateRss(props)
// 生成
generateSitemapXml(props)
// 生成全文索引 - 仅在 yarn build 时执行 && process.env.npm_lifecycle_event === 'build'

916
public/css/aos.css Normal file
View File

@@ -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);
}

View File

@@ -1,5 +1,5 @@
/* 图片阴影 */
.notion-asset-wrapper-image img {
article .notion-asset-wrapper-image img {
box-shadow:
rgba(50, 50, 93, 0.25) 0px 13px 27px -5px,
rgba(0, 0, 0, 0.3) 0px 8px 16px -8px;

672
public/js/aos.js Normal file
View File

@@ -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
}
])
})

View File

@@ -3,7 +3,7 @@ const idFlutteringRibbon = 'canvasFlutteringRibbon'
function destroyFlutteringRibbon() {
const ribbon = document.getElementById(idFlutteringRibbon)
if (ribbon && ribbon.parentNode) {
if (ribbon && ribbon.parentNode && ribbon.parentNode.contains(ribbon)) {
ribbon.parentNode.removeChild(ribbon)
}
}

View File

@@ -109,7 +109,7 @@ function createNest() {
function destroyNest() {
const nest = document.getElementById(idNest)
if(nest && nest.parentNode){
if (nest && nest.parentNode && nest.parentNode.contains(nest)) {
nest.parentNode.removeChild(nest)
}
}

View File

@@ -80,7 +80,7 @@ function createRibbon() {
function destroyRibbon() {
const ribbon = document.getElementById(idRibbon)
if (ribbon && ribbon.parentNode) {
if (ribbon && ribbon.parentNode && ribbon.parentNode.contains(ribbon)) {
ribbon.parentNode.removeChild(ribbon)
}
}

View File

@@ -165,9 +165,11 @@ function createSakura() {
function stopp() {
if (staticx) {
var child = document.getElementById(id)
child.parentNode.removeChild(child)
window.cancelAnimationFrame(stop)
staticx = false
if (child && child.parentNode && child.parentNode.contains(child)) {
child.parentNode.removeChild(child)
window.cancelAnimationFrame(stop)
staticx = false
}
} else {
startSakura()
}
@@ -177,7 +179,7 @@ function createSakura() {
// 销毁樱花雨
function destroySakura() {
const sakura = document.getElementById(idSakura)
if (sakura && sakura.parentNode) {
if (sakura && sakura.parentNode && sakura.parentNode.contains(sakura)) {
sakura.parentNode.removeChild(sakura)
}
}

626
public/js/typed.min.js vendored Normal file
View File

@@ -0,0 +1,626 @@
/*!
*
* typed.js - A JavaScript Typing Animation Library
* Author: Matt Boldt <me@mattboldt.com>
* 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

View File

@@ -272,3 +272,7 @@ a.avatar-wrapper {
margin-right: 20px;
}
}
img {
display: unset;
}

View File

@@ -179,10 +179,12 @@ const LayoutSlug = props => {
{lock ? (
<PostLock validPassword={validPassword} />
) : (
<div id='article-wrapper'>
<div>
<PostMeta post={post} />
<NotionPage post={post} />
<ShareBar post={post} />
<div id='article-wrapper'>
<NotionPage post={post} />
<ShareBar post={post} />
</div>
<Comment frontMatter={post} />
</div>
)}

View File

@@ -1,16 +1,16 @@
import TagItemMini from './TagItemMini'
import Comment from '@/components/Comment'
import NotionPage from '@/components/NotionPage'
import ShareBar from '@/components/ShareBar'
import { useGlobal } from '@/lib/global'
import Link from 'next/link'
import ArticleAround from './ArticleAround'
import { AdSlot } from '@/components/GoogleAdsense'
import LazyImage from '@/components/LazyImage'
import { formatDateFmt } from '@/lib/utils/formatDate'
import WWAds from '@/components/WWAds'
import NotionIcon from '@/components/NotionIcon'
import NotionPage from '@/components/NotionPage'
import ShareBar from '@/components/ShareBar'
import WWAds from '@/components/WWAds'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { formatDateFmt } from '@/lib/utils/formatDate'
import Link from 'next/link'
import ArticleAround from './ArticleAround'
import TagItemMini from './TagItemMini'
/**
*
@@ -25,66 +25,75 @@ export default function ArticleDetail(props) {
return <></>
}
return (
<div id="container" className={`${fullWidth ? 'px-10' : 'max-w-5xl '} overflow-x-auto flex-grow mx-auto w-screen md:w-full`}>
<div
id='container'
className={`${fullWidth ? 'px-10' : 'max-w-5xl '} overflow-x-auto flex-grow mx-auto w-screen md:w-full`}>
{post?.type && !post?.type !== 'Page' && post?.pageCover && (
<div className="w-full relative md:flex-shrink-0 overflow-hidden">
<LazyImage alt={post.title} src={post?.pageCover} className='object-cover max-h-[60vh] w-full' />
<div className='w-full relative md:flex-shrink-0 overflow-hidden'>
<LazyImage
alt={post.title}
src={post?.pageCover}
className='object-cover max-h-[60vh] w-full'
/>
</div>
)}
<article itemScope itemType="https://schema.org/Movie" className="subpixel-antialiased overflow-y-hidden py-10 px-5 lg:pt-24 md:px-32 dark:border-gray-700 bg-white dark:bg-hexo-black-gray" >
<article
itemScope
itemType='https://schema.org/Movie'
className='subpixel-antialiased overflow-y-hidden py-10 px-5 lg:pt-24 md:px-32 dark:border-gray-700 bg-white dark:bg-hexo-black-gray'>
<header>
{/* 文章Title */}
<div className="font-bold text-4xl text-black dark:text-white">
{siteConfig('POST_TITLE_ICON') && <NotionIcon icon={post?.pageIcon} />}{post.title}
<div className='font-bold text-4xl text-black dark:text-white'>
{siteConfig('POST_TITLE_ICON') && (
<NotionIcon icon={post?.pageIcon} />
)}
{post.title}
</div>
<section className="flex-wrap flex mt-2 text-gray-400 dark:text-gray-400 font-light leading-8">
<section className='flex-wrap flex mt-2 text-gray-400 dark:text-gray-400 font-light leading-8'>
<div>
{post?.category && (<>
{post?.category && (
<>
<Link
href={`/category/${post.category}`}
passHref
className="cursor-pointer text-md mr-2 hover:text-black dark:hover:text-white border-b dark:border-gray-500 border-dashed">
<i className="mr-1 fas fa-folder-open" />
className='cursor-pointer text-md mr-2 hover:text-black dark:hover:text-white border-b dark:border-gray-500 border-dashed'>
<i className='mr-1 fas fa-folder-open' />
{post.category}
</Link>
<span className='mr-2'>|</span>
</>)}
<span className='mr-2'>|</span>
</>
)}
{post?.type !== 'Page' && (<>
<Link
href={`/archive#${formatDateFmt(post?.publishDate, 'yyyy-MM')}`}
passHref
className="pl-1 mr-2 cursor-pointer hover:text-gray-700 dark:hover:text-gray-200 border-b dark:border-gray-500 border-dashed">
{post?.type !== 'Page' && (
<>
<Link
href={`/archive#${formatDateFmt(post?.publishDate, 'yyyy-MM')}`}
passHref
className='pl-1 mr-2 cursor-pointer hover:text-gray-700 dark:hover:text-gray-200 border-b dark:border-gray-500 border-dashed'>
{post?.publishDay}
</Link>
<span className='mr-2'>|</span>
<span className='mx-2 text-gray-400 dark:text-gray-500'>
{locale.COMMON.LAST_EDITED_TIME}: {post.lastEditedDay}
</span>
</>
)}
{post?.publishDay}
</Link>
<span className='mr-2'>|</span>
<span className='mx-2 text-gray-400 dark:text-gray-500'>
{locale.COMMON.LAST_EDITED_TIME}: {post.lastEditedDay}
</span>
</>)}
<div className='my-2'>
<div className='my-2'>
{post.tagItems && (
<div className="flex flex-nowrap overflow-x-auto">
{post.tagItems.map(tag => (
<TagItemMini key={tag.name} tag={tag} />
))}
</div>
<div className='flex flex-nowrap overflow-x-auto'>
{post.tagItems.map(tag => (
<TagItemMini key={tag.name} tag={tag} />
))}
</div>
)}
</div>
</div>
</div>
</section>
<WWAds className='w-full' orientation='horizontal'/>
<WWAds className='w-full' orientation='horizontal' />
</header>
{/* Notion文章主体 */}
@@ -93,17 +102,16 @@ export default function ArticleDetail(props) {
</section>
<section>
<AdSlot type='in-article'/>
{/* 分享 */}
<ShareBar post={post} />
<AdSlot type='in-article' />
{/* 分享 */}
<ShareBar post={post} />
</section>
</article>
{post?.type === 'Post' && <ArticleAround prev={prev} next={next} /> }
{post?.type === 'Post' && <ArticleAround prev={prev} next={next} />}
{/* 评论互动 */}
<div className="duration-200 shadow py-6 px-12 w-screen md:w-full overflow-x-auto dark:border-gray-700 bg-white dark:bg-hexo-black-gray">
<div className='duration-200 shadow py-6 px-12 w-screen md:w-full overflow-x-auto dark:border-gray-700 bg-white dark:bg-hexo-black-gray'>
<Comment frontMatter={post} />
</div>
</div>

View File

@@ -1,3 +1,4 @@
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { GameListIndexCombine } from './GameListIndexCombine'
import PaginationSimple from './PaginationSimple'
@@ -9,7 +10,8 @@ import PaginationSimple from './PaginationSimple'
export const BlogListPage = props => {
const { page = 1, postCount } = props
const { NOTION_CONFIG } = useGlobal()
const totalPage = Math.ceil(postCount / NOTION_CONFIG)
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', null, NOTION_CONFIG)
const totalPage = Math.ceil(postCount / POSTS_PER_PAGE)
const showNext = page < totalPage
return (

View File

@@ -12,7 +12,7 @@ export default function BottomMenuBar({ post, className }) {
return (
<>
{/* 移动端底部导航按钮 */}
<div className='bottom-button-group md:hidden w-screen h-14 px-4 fixed flex items-center justify-between right-left bottom-0 z-30 bg-white border-t dark:border-gray-800'>
<div className='dark:bg-hexo-black-gray bottom-button-group md:hidden w-screen h-14 px-4 fixed flex items-center justify-between right-left bottom-0 z-30 bg-white border-t dark:border-gray-800'>
<div className='w-full'>
<MobileButtonPageNav />
</div>

View File

@@ -1,7 +0,0 @@
export default function LoadingCover() {
return <div id='cover-loading' className={'z-50 opacity-50pointer-events-none transition-all duration-300'}>
<div className='w-full h-screen flex justify-center items-center'>
<i className="fa-solid fa-spinner text-2xl text-black dark:text-white animate-spin"> </i>
</div>
</div>
}

View File

@@ -3,6 +3,7 @@
import Comment from '@/components/Comment'
import { AdSlot } from '@/components/GoogleAdsense'
import Live2D from '@/components/Live2D'
import LoadingCover from '@/components/LoadingCover'
import NotionIcon from '@/components/NotionIcon'
import NotionPage from '@/components/NotionPage'
import ShareBar from '@/components/ShareBar'
@@ -113,6 +114,11 @@ const LayoutBase = props => {
setFilteredNavPages(getNavPagesWithLatest(allNavPages, latestPosts, post))
}, [router])
const GITBOOK_LOADING_COVER = siteConfig(
'GITBOOK_LOADING_COVER',
true,
CONFIG
)
return (
<ThemeGlobalGitbook.Provider
value={{
@@ -237,6 +243,8 @@ const LayoutBase = props => {
)}
</main>
{GITBOOK_LOADING_COVER && <LoadingCover />}
{/* 移动端导航抽屉 */}
<PageNavDrawer {...props} filteredNavPages={filteredNavPages} />
@@ -333,8 +341,10 @@ const LayoutSlug = props => {
{/* Notion文章主体 */}
{post && (
<section id='article-wrapper' className='px-1'>
<NotionPage post={post} />
<section className='px-1'>
<div id='article-wrapper'>
<NotionPage post={post} />
</div>
{/* 分享 */}
<ShareBar post={post} />

View File

@@ -4,13 +4,15 @@ const NotionPage = dynamic(() => import('@/components/NotionPage'))
const Announcement = ({ post, className }) => {
if (post?.blockMap) {
return <div >
{post && (
<div id="announcement-content">
<NotionPage post={post} />
</div>
)}
</div>
return (
<div>
{post && (
<div id='announcement-content'>
<NotionPage post={post} />
</div>
)}
</div>
)
} else {
return <></>
}

View File

@@ -19,18 +19,31 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
siteConfig('HEO_POST_LIST_COVER', null, CONFIG) &&
post?.pageCoverThumbnail &&
!showPreview
const POST_TWO_COLS = siteConfig('HEO_HOME_POST_TWO_COLS', true, CONFIG)
const COVER_HOVER_ENLARGE = siteConfig(
'HEO_POST_LIST_COVER_HOVER_ENLARGE',
true,
CONFIG
)
return (
<article
className={` ${siteConfig('HEO_POST_LIST_COVER_HOVER_ENLARGE', null, CONFIG) ? ' hover:scale-110 transition-all duration-150' : ''}`}>
className={` ${COVER_HOVER_ENLARGE} ? ' hover:scale-110 transition-all duration-150' : ''}`}>
<div
data-wow-delay='.2s'
className={
'wow fadeInUp border bg-white dark:bg-[#1e1e1e] flex mb-4 flex-col h-[23rem] md:h-52 md:flex-row 2xl:h-96 2xl:flex-col group w-full dark:border-gray-600 hover:border-indigo-600 dark:hover:border-yellow-600 duration-300 transition-colors justify-between overflow-hidden rounded-xl'
(POST_TWO_COLS ? '2xl:h-96 2xl:flex-col' : '') +
' wow fadeInUp border bg-white dark:bg-[#1e1e1e] flex mb-4 flex-col h-[23rem] md:h-52 md:flex-row group w-full dark:border-gray-600 hover:border-indigo-600 dark:hover:border-yellow-600 duration-300 transition-colors justify-between overflow-hidden rounded-xl'
}>
{/* 图片封面 */}
{showPageCover && (
<Link href={post?.href} passHref legacyBehavior>
<div className='w-full md:w-5/12 2xl:w-full overflow-hidden'>
<div
className={
(POST_TWO_COLS ? ' 2xl:w-full' : '') +
' w-full md:w-5/12 overflow-hidden cursor-pointer select-none'
}>
<LazyImage
priority={index === 0}
src={post?.pageCoverThumbnail}
@@ -44,7 +57,8 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
{/* 文字区块 */}
<div
className={
'flex p-6 2xl:p-4 flex-col justify-between h-48 md:h-full 2xl:h-48 w-full md:w-7/12 2xl:w-full'
(POST_TWO_COLS ? '2xl:p-4 2xl:h-48 2xl:w-full' : '') +
' flex p-6 flex-col justify-between h-48 md:h-full w-full md:w-7/12'
}>
<header>
{/* 分类 */}

View File

@@ -1,5 +1,6 @@
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import CONFIG from '../config'
import BlogPostCard from './BlogPostCard'
import BlogPostListEmpty from './BlogPostListEmpty'
import PaginationNumber from './PaginationNumber'
@@ -14,16 +15,18 @@ import PaginationNumber from './PaginationNumber'
*/
const BlogPostListPage = ({ page = 1, posts = [], postCount, siteInfo }) => {
const { NOTION_CONFIG } = useGlobal()
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', null, NOTION_CONFIG)
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', 12, NOTION_CONFIG)
const totalPage = Math.ceil(postCount / POSTS_PER_PAGE)
const showPagination = postCount >= POSTS_PER_PAGE
const POST_TWO_COLS = siteConfig('HEO_HOME_POST_TWO_COLS', true, CONFIG)
if (!posts || posts.length === 0 || page > totalPage) {
return <BlogPostListEmpty />
} else {
return (
<div id='container' className='w-full'>
{/* 文章列表 */}
<div className='2xl:grid 2xl:grid-cols-2 grid-cols-1 gap-5'>
<div
className={`${POST_TWO_COLS && '2xl:grid 2xl:grid-cols-2'} grid-cols-1 gap-5`}>
{posts?.map(post => (
<BlogPostCard
index={posts.indexOf(post)}

View File

@@ -19,7 +19,7 @@ const BlogPostListScroll = ({
showSummary = siteConfig('HEO_POST_LIST_SUMMARY', null, CONFIG),
siteInfo
}) => {
const { NOTION_CONFIG } = useGlobal()
const { locale, NOTION_CONFIG } = useGlobal()
const [page, updatePage] = useState(1)
const POSTS_PER_PAGE = siteConfig('POSTS_PER_PAGE', null, NOTION_CONFIG)
const postsToShow = getListByPage(posts, page, POSTS_PER_PAGE)
@@ -59,15 +59,16 @@ const BlogPostListScroll = ({
})
const targetRef = useRef(null)
const { locale } = useGlobal()
const POST_TWO_COLS = siteConfig('HEO_HOME_POST_TWO_COLS', true, CONFIG)
if (!postsToShow || postsToShow.length === 0) {
return <BlogPostListEmpty currentSearch={currentSearch} />
} else {
return (
<div id='container' ref={targetRef} className='w-full'>
{/* 文章列表 */}
<div className='2xl:grid 2xl:grid-cols-2 grid-cols-1 gap-5'>
<div
className={`${POST_TWO_COLS && '2xl:grid 2xl:grid-cols-2'} grid-cols-1 gap-5`}>
{' '}
{postsToShow.map(post => (
<BlogPostCard
key={post.id}

View File

@@ -32,8 +32,8 @@ export default function CategoryBar(props) {
return (
<div
id='category-bar'
className={`flex flex-nowrap justify-between items-center h-12 mb-4 space-x-2 w-full lg:bg-white dark:lg:bg-[#1e1e1e]
${border ? 'lg:border lg:hover:border dark:lg:border-gray-800 hover:border-indigo-600 dark:hover:border-yellow-600 ' : ''} py-2 lg:px-2 rounded-xl transition-colors duration-200`}>
className={`wow fadeInUp flex flex-nowrap justify-between items-center h-12 mb-4 space-x-2 w-full lg:bg-white dark:lg:bg-[#1e1e1e]
${border ? 'lg:border lg:hover:border dark:lg:border-gray-800 hover:border-indigo-600 dark:hover:border-yellow-600 ' : ''} py-2 lg:px-2 rounded-xl transition-colors duration-200`}>
<div
id='category-bar-items'
ref={categoryBarItemsRef}

View File

@@ -383,7 +383,7 @@ function TodayCard({ cRef, siteInfo }) {
}
/>
<div id='more' className='select-none'>
{locale.COMMON.MORE}
{locale.COMMON.RECOMMEND_POSTS}
</div>
</div>
</div>

View File

@@ -23,11 +23,12 @@ export function InfoCard(props) {
const url2 = siteConfig('HEO_INFO_CARD_URL2', null, CONFIG)
const icon2 = siteConfig('HEO_INFO_CARD_ICON2', null, CONFIG)
return (
<Card className='bg-[#4f65f0] dark:bg-yellow-600 text-white flex flex-col w-72 overflow-hidden relative'>
<Card className='wow fadeInUp bg-[#4f65f0] dark:bg-yellow-600 text-white flex flex-col w-72 overflow-hidden relative'>
{/* 信息卡牌第一行 */}
<div className='flex justify-between'>
{/* 问候语 */}
<GreetingsWords />
{/* 头像 */}
<div
className={`${isSlugPage ? 'absolute right-0 -mt-8 -mr-6 hover:opacity-0 hover:scale-150 blur' : 'cursor-pointer'} justify-center items-center flex dark:text-gray-100 transform transitaion-all duration-200`}>
<LazyImage
@@ -42,9 +43,7 @@ export function InfoCard(props) {
<h2 className='text-3xl font-extrabold mt-3'>{siteConfig('AUTHOR')}</h2>
{/* 公告栏 */}
<div>
<Announcement post={notice} style={{ color: 'white !important' }} />
</div>
<Announcement post={notice} style={{ color: 'white !important' }} />
<div className='flex justify-between'>
<div className='flex space-x-3 hover:text-black dark:hover:text-white'>

View File

@@ -1,8 +0,0 @@
export default function LoadingCover () {
return (<div id="loading-cover" className={'md:-mt-20 flex-grow dark:text-white text-black animate__animated animate__fadeIn flex flex-col justify-center z-50 w-full h-screen container mx-auto'}>
<div className="mx-auto">
<i className="fas fa-spinner animate-spin"/>
</div>
</div>
)
}

View File

@@ -34,23 +34,25 @@ export default function SideRight(props) {
return (
<div id='sideRight' className='hidden xl:block w-72 space-y-4 h-full'>
<InfoCard {...props} className='w-72' />
<InfoCard {...props} className='w-72 wow fadeInUp' />
<div className='sticky top-20 space-y-4'>
{/* 文章页显示目录 */}
{post && post.toc && post.toc.length > 0 && (
<Card className='bg-white dark:bg-[#1e1e1e]'>
<Card className='bg-white dark:bg-[#1e1e1e] wow fadeInUp'>
<Catalog toc={post.toc} />
</Card>
)}
{/* 联系交流群 */}
<TouchMeCard />
<div className='wow fadeInUp'>
<TouchMeCard />
</div>
{/* 最新文章列表 */}
<div
className={
'border hover:border-indigo-600 dark:hover:border-yellow-600 duration-200 dark:border-gray-700 dark:bg-[#1e1e1e] dark:text-white rounded-xl lg:p-6 p-4 hidden lg:block bg-white'
'border wow fadeInUp hover:border-indigo-600 dark:hover:border-yellow-600 duration-200 dark:border-gray-700 dark:bg-[#1e1e1e] dark:text-white rounded-xl lg:p-6 p-4 hidden lg:block bg-white'
}>
<LatestPostsGroupMini {...props} />
</div>

View File

@@ -1,8 +1,7 @@
import FlipCard from '@/components/FlipCard'
import { siteConfig } from '@/lib/config'
import Link from 'next/link'
import CONFIG from '../config'
import { siteConfig } from '@/lib/config'
/**
* 交流频道
@@ -13,23 +12,33 @@ export default function TouchMeCard() {
return <></>
}
return (
<div className={'relative h-28 text-white flex flex-col'}>
<FlipCard
className='cursor-pointer lg:p-6 p-4 border rounded-xl bg-[#4f65f0] dark:bg-yellow-600 dark:border-gray-600'
frontContent={
<div className='h-full'>
<h2 className='font-[1000] text-3xl'>{siteConfig('HEO_SOCIAL_CARD_TITLE_1', null, CONFIG)}</h2>
<h3 className='pt-2'>{siteConfig('HEO_SOCIAL_CARD_TITLE_2', null, CONFIG)}</h3>
<div className='absolute left-0 top-0 w-full h-full' style={{ background: 'url(https://bu.dusays.com/2023/05/16/64633c4cd36a9.png) center center no-repeat' }}></div>
</div>}
backContent={<Link href={siteConfig('HEO_SOCIAL_CARD_URL', null, CONFIG)}>
<div className='font-[1000] text-xl h-full'>
{siteConfig('HEO_SOCIAL_CARD_TITLE_3', null, CONFIG)}
</div>
</Link>}
/>
</div>
<div className={'relative h-28 text-white flex flex-col'}>
<FlipCard
className='cursor-pointer lg:p-6 p-4 border rounded-xl bg-[#4f65f0] dark:bg-yellow-600 dark:border-gray-600'
frontContent={
<div className='h-full'>
<h2 className='font-[1000] text-3xl'>
{siteConfig('HEO_SOCIAL_CARD_TITLE_1', null, CONFIG)}
</h2>
<h3 className='pt-2'>
{siteConfig('HEO_SOCIAL_CARD_TITLE_2', null, CONFIG)}
</h3>
<div
className='absolute left-0 top-0 w-full h-full'
style={{
background:
'url(https://bu.dusays.com/2023/05/16/64633c4cd36a9.png) center center no-repeat'
}}></div>
</div>
}
backContent={
<Link href={siteConfig('HEO_SOCIAL_CARD_URL', null, CONFIG)}>
<div className='font-[1000] text-xl h-full'>
{siteConfig('HEO_SOCIAL_CARD_TITLE_3', null, CONFIG)}
</div>
</Link>
}
/>
</div>
)
}

View File

@@ -1,4 +1,7 @@
const CONFIG = {
HEO_HOME_POST_TWO_COLS: true, // 首页博客两列显示若为false则只显示一列
HEO_LOADING_COVER: true, // 页面加载的遮罩动画
HEO_HOME_BANNER_ENABLE: true,
HEO_SITE_CREATE_TIME: '2021-09-21', // 建站日期,用于计算网站运行的第几天

View File

@@ -10,6 +10,7 @@ import Comment from '@/components/Comment'
import { AdSlot } from '@/components/GoogleAdsense'
import { HashTag } from '@/components/HeroIcons'
import LazyImage from '@/components/LazyImage'
import LoadingCover from '@/components/LoadingCover'
import replaceSearchResult from '@/components/Mark'
import NotionPage from '@/components/NotionPage'
import ShareBar from '@/components/ShareBar'
@@ -82,6 +83,7 @@ const LayoutBase = props => {
false,
CONFIG
)
const HEO_LOADING_COVER = siteConfig('HEO_LOADING_COVER', true, CONFIG)
// 加载wow动画
useEffect(() => {
@@ -121,6 +123,8 @@ const LayoutBase = props => {
{/* 页脚 */}
<Footer title={siteConfig('TITLE')} />
{HEO_LOADING_COVER && <LoadingCover />}
</div>
)
}
@@ -284,14 +288,17 @@ const LayoutSlug = props => {
return (
<>
<div
className={`article h-full w-full ${fullWidth ? '' : 'xl:max-w-5xl'} ${hasCode ? 'xl:w-[73.15vw]' : ''} lg:hover:shadow lg:border rounded-2xl lg:px-2 lg:py-4 bg-white dark:bg-[#18171d] dark:border-gray-600`}>
className={`article h-full w-full ${fullWidth ? '' : 'xl:max-w-5xl'} ${hasCode ? 'xl:w-[73.15vw]' : ''} bg-white dark:bg-[#18171d] dark:border-gray-600 lg:hover:shadow lg:border rounded-2xl lg:px-2 lg:py-4 `}>
{/* 文章锁 */}
{lock && <PostLock validPassword={validPassword} />}
{!lock && (
<div id='article-wrapper' className='mx-auto md:w-full md:px-5'>
<div className='mx-auto md:w-full md:px-5'>
{/* 文章主体 */}
<article itemScope itemType='https://schema.org/Movie'>
<article
id='article-wrapper'
itemScope
itemType='https://schema.org/Movie'>
{/* Notion文章主体 */}
<section
className='wow fadeInUp p-5 justify-center mx-auto'

View File

@@ -26,10 +26,7 @@ const Hero = props => {
updateHeaderHeight()
if (!typed && window && document.getElementById('typed')) {
loadExternalResource(
'https://cdn.bootcdn.net/ajax/libs/typed.js/2.0.12/typed.min.js',
'js'
).then(() => {
loadExternalResource('/js/typed.min.js', 'js').then(() => {
if (window.Typed) {
changeType(
new window.Typed('#typed', {

View File

@@ -1,16 +1,16 @@
import Card from './Card'
import CategoryGroup from './CategoryGroup'
import LatestPostsGroup from './LatestPostsGroup'
import TagGroups from './TagGroups'
import Catalog from './Catalog'
import { InfoCard } from './InfoCard'
import { AnalyticsCard } from './AnalyticsCard'
import CONFIG from '../config'
import dynamic from 'next/dynamic'
import Announcement from './Announcement'
import { useGlobal } from '@/lib/global'
import Live2D from '@/components/Live2D'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import dynamic from 'next/dynamic'
import CONFIG from '../config'
import { AnalyticsCard } from './AnalyticsCard'
import Announcement from './Announcement'
import Card from './Card'
import Catalog from './Catalog'
import CategoryGroup from './CategoryGroup'
import { InfoCard } from './InfoCard'
import LatestPostsGroup from './LatestPostsGroup'
import TagGroups from './TagGroups'
const HexoRecentComments = dynamic(() => import('./HexoRecentComments'))
const FaceBookPage = dynamic(
@@ -33,8 +33,17 @@ const FaceBookPage = dynamic(
*/
export default function SideRight(props) {
const {
post, currentCategory, categories, latestPosts, tags,
currentTag, showCategory, showTag, rightAreaSlot, notice, className
post,
currentCategory,
categories,
latestPosts,
tags,
currentTag,
showCategory,
showTag,
rightAreaSlot,
notice,
className
} = props
const { locale } = useGlobal()
@@ -45,44 +54,54 @@ export default function SideRight(props) {
}
return (
<div id='sideRight' className={className}>
<InfoCard {...props} />
{siteConfig('HEXO_WIDGET_ANALYTICS', null, CONFIG) && <AnalyticsCard {...props} />}
<div
id='sideRight'
className={` lg:w-80 lg:pt-8 ${post ? 'lg:pt-0' : 'lg:pt-4'}`}>
<div className='sticky top-8 space-y-4'>
{post && post.toc && post.toc.length > 1 && (
<Card>
<Catalog toc={post.toc} />
</Card>
)}
{showCategory && (
<Card>
<div className='ml-2 mb-1 '>
<i className='fas fa-th' /> {locale.COMMON.CATEGORY}
</div>
<CategoryGroup
currentCategory={currentCategory}
categories={categories}
/>
</Card>
)}
{showTag && (
<Card>
<TagGroups tags={tags} currentTag={currentTag} />
</Card>
)}
{siteConfig('HEXO_WIDGET_LATEST_POSTS', null, CONFIG) && latestPosts && latestPosts.length > 0 && <Card>
<LatestPostsGroup {...props} />
</Card>}
<InfoCard {...props} />
{siteConfig('HEXO_WIDGET_ANALYTICS', null, CONFIG) && (
<AnalyticsCard {...props} />
)}
<Announcement post={notice}/>
{showCategory && (
<Card>
<div className='ml-2 mb-1 '>
<i className='fas fa-th' /> {locale.COMMON.CATEGORY}
</div>
<CategoryGroup
currentCategory={currentCategory}
categories={categories}
/>
</Card>
)}
{showTag && (
<Card>
<TagGroups tags={tags} currentTag={currentTag} />
</Card>
)}
{siteConfig('HEXO_WIDGET_LATEST_POSTS', null, CONFIG) &&
latestPosts &&
latestPosts.length > 0 && (
<Card>
<LatestPostsGroup {...props} />
</Card>
)}
{siteConfig('COMMENT_WALINE_SERVER_URL') && siteConfig('COMMENT_WALINE_RECENT') && <HexoRecentComments/>}
<Announcement post={notice} />
<div className='sticky top-20'>
{post && post.toc && post.toc.length > 1 && <Card>
<Catalog toc={post.toc} />
</Card>}
{siteConfig('COMMENT_WALINE_SERVER_URL') &&
siteConfig('COMMENT_WALINE_RECENT') && <HexoRecentComments />}
{rightAreaSlot}
<FaceBookPage/>
<FaceBookPage />
<Live2D />
</div>
</div>
)
}

View File

@@ -141,10 +141,7 @@ const LayoutBase = props => {
</div>
{/* 右侧栏 */}
<SideRight
{...props}
className={`space-y-4 lg:w-80 pt-4 ${post ? 'lg:pt-0' : 'lg:pt-4'}`}
/>
<SideRight {...props} />
</div>
</main>
@@ -290,10 +287,9 @@ const LayoutSlug = props => {
{lock && <ArticleLock validPassword={validPassword} />}
{!lock && (
<div
id='article-wrapper'
className='overflow-x-auto flex-grow mx-auto md:w-full md:px-5 '>
<div className='overflow-x-auto flex-grow mx-auto md:w-full md:px-5 '>
<article
id='article-wrapper'
itemScope
itemType='https://schema.org/Movie'
className='subpixel-antialiased overflow-y-hidden'>

View File

@@ -1,4 +1,3 @@
'use client'
/**
@@ -7,21 +6,21 @@
* 2. 内容大部分是在此文件中写死notion数据从props参数中传进来
* 3. 您可在此网站找到更多喜欢的组件 https://www.tailwind-kit.com/
*/
import Loading from '@/components/Loading'
import NotionPage from '@/components/NotionPage'
import Header from './components/Header'
import Footer from './components/Footer'
import Hero from './components/Hero'
import { siteConfig } from '@/lib/config'
import { isBrowser } from '@/lib/utils'
import { useRouter } from 'next/router'
import { useEffect } from 'react'
import Features from './components/Features'
import FeaturesBlocks from './components/FeaturesBlocks'
import Testimonials from './components/Testimonials'
import Footer from './components/Footer'
import Header from './components/Header'
import Hero from './components/Hero'
import Newsletter from './components/Newsletter'
import { useRouter } from 'next/router'
import CONFIG from './config'
import Loading from '@/components/Loading'
import { isBrowser } from '@/lib/utils'
import { siteConfig } from '@/lib/config'
import { Pricing } from './components/Pricing'
import { useEffect } from 'react'
import Testimonials from './components/Testimonials'
import CONFIG from './config'
/**
* 布局框架
@@ -30,22 +29,23 @@ import { useEffect } from 'react'
* @param {*} props
* @returns
*/
const LayoutBase = (props) => {
const LayoutBase = props => {
const { children } = props
return <div id='theme-landing' className={`${siteConfig('FONT_STYLE')} scroll-smooth overflow-hidden flex flex-col justify-between bg-white dark:bg-black`}>
return (
<div
id='theme-landing'
className={`${siteConfig('FONT_STYLE')} scroll-smooth overflow-hidden flex flex-col justify-between bg-white dark:bg-black`}>
{/* 顶部导航栏 */}
<Header />
{/* 顶部导航栏 */}
<Header />
{/* 内容 */}
<div id='content-wrapper'>{children}</div>
{/* 内容 */}
<div id='content-wrapper'>
{children}
</div>
{/* 底部页脚 */}
<Footer />
{/* 底部页脚 */}
<Footer />
</div>
)
}
/**
@@ -53,16 +53,16 @@ const LayoutBase = (props) => {
* @param {*} props
* @returns
*/
const LayoutIndex = (props) => {
const LayoutIndex = props => {
return (
<>
<Hero />
<Features />
<FeaturesBlocks />
<Testimonials />
<Pricing/>
<Newsletter />
</>
<>
<Hero />
<Features />
<FeaturesBlocks />
<Testimonials />
<Pricing />
<Newsletter />
</>
)
}
@@ -71,7 +71,7 @@ const LayoutIndex = (props) => {
* @param {*} props
* @returns
*/
const LayoutSlug = (props) => {
const LayoutSlug = props => {
const { post } = props
// 如果 是 /article/[slug] 的文章路径则进行重定向到另一个域名
@@ -79,49 +79,90 @@ const LayoutSlug = (props) => {
useEffect(() => {
// 404
if (!post) {
setTimeout(() => {
if (isBrowser) {
const article = document.getElementById('notion-article')
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
setTimeout(
() => {
if (isBrowser) {
const article = document.getElementById('notion-article')
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
}
}
}
}, siteConfig('POST_WAITING_TIME_FOR_404') * 1000)
},
siteConfig('POST_WAITING_TIME_FOR_404') * 1000
)
}
}, [post])
if (JSON.parse(siteConfig('LANDING_POST_REDIRECT_ENABLE', null, CONFIG)) && isBrowser && router.route === '/[prefix]/[slug]') {
const redirectUrl = siteConfig('LANDING_POST_REDIRECT_URL', null, CONFIG) + router.asPath.replace('?theme=landing', '')
if (
JSON.parse(siteConfig('LANDING_POST_REDIRECT_ENABLE', null, CONFIG)) &&
isBrowser &&
router.route === '/[prefix]/[slug]'
) {
const redirectUrl =
siteConfig('LANDING_POST_REDIRECT_URL', null, CONFIG) +
router.asPath.replace('?theme=landing', '')
router.push(redirectUrl)
return <div id='theme-landing'><Loading /></div>
return (
<div id='theme-landing'>
<Loading />
</div>
)
}
return <>
<div id='container-inner' className='mx-auto max-w-screen-lg p-12'>
<NotionPage {...props} />
return (
<>
<div id='container-inner' className='mx-auto max-w-screen-lg p-12'>
<div id='article-wrapper'>
<NotionPage {...props} />
</div>
</div>
</>
)
}
// 其他布局暂时留空
const LayoutSearch = (props) => <><Hero /></>
const LayoutArchive = (props) => <><Hero /></>
const Layout404 = (props) => <><Hero /></>
const LayoutCategoryIndex = (props) => <><Hero /></>
const LayoutPostList = (props) => <><Hero /></>
const LayoutTagIndex = (props) => <><Hero /></>
const LayoutSearch = props => (
<>
<Hero />
</>
)
const LayoutArchive = props => (
<>
<Hero />
</>
)
const Layout404 = props => (
<>
<Hero />
</>
)
const LayoutCategoryIndex = props => (
<>
<Hero />
</>
)
const LayoutPostList = props => (
<>
<Hero />
</>
)
const LayoutTagIndex = props => (
<>
<Hero />
</>
)
export {
CONFIG as THEME_CONFIG,
LayoutBase,
LayoutIndex,
LayoutSearch,
LayoutArchive,
LayoutSlug,
Layout404,
LayoutPostList,
LayoutArchive,
LayoutBase,
LayoutCategoryIndex,
LayoutTagIndex
LayoutIndex,
LayoutPostList,
LayoutSearch,
LayoutSlug,
LayoutTagIndex,
CONFIG as THEME_CONFIG
}

View File

@@ -21,10 +21,7 @@ const Hero = props => {
useEffect(() => {
updateHeaderHeight()
if (!typed && window && document.getElementById('typed')) {
loadExternalResource(
'https://cdn.bootcdn.net/ajax/libs/typed.js/2.0.12/typed.min.js',
'js'
).then(() => {
loadExternalResource('/js/typed.min.js', 'js').then(() => {
if (window.Typed) {
changeType(
new window.Typed('#typed', {

View File

@@ -254,9 +254,7 @@ const LayoutSlug = props => {
{lock && <ArticleLock validPassword={validPassword} />}
{!lock && (
<div
id='article-wrapper'
className='overflow-x-auto md:w-full px-3 '>
<div className='overflow-x-auto md:w-full px-3 '>
{/* 文章信息 */}
{post?.type && post?.type === 'Post' && (
<>
@@ -268,7 +266,7 @@ const LayoutSlug = props => {
)}
<div className='lg:px-10 subpixel-antialiased'>
<article itemScope>
<article id='article-wrapper' itemScope>
{/* Notion文章主体 */}
<section
data-wow-delay='.1s'

View File

@@ -1,18 +1,37 @@
import { useGlobal } from '@/lib/global'
import CategoryItem from './CategoryItem'
/**
* 分类
* @param {*} param0
* @returns
*/
const CategoryGroup = ({ currentCategory, categoryOptions }) => {
const { locale } = useGlobal()
if (!categoryOptions) {
return <></>
}
return <div id='category-list' className='pt-4'>
<div className='mb-2'><i className='mr-2 fas fa-th' />分类</div>
<div className='flex flex-wrap'>
{categoryOptions?.map(category => {
const selected = currentCategory === category.name
return <CategoryItem key={category.name} selected={selected} category={category.name} categoryCount={category.count} />
})}
return (
<div id='category-list' className='pt-4'>
<div className='mb-2'>
<i className='mr-2 fas fa-th' />
{locale.COMMON.CATEGORY}
</div>
<div className='flex flex-wrap'>
{categoryOptions?.map(category => {
const selected = currentCategory === category.name
return (
<CategoryItem
key={category.name}
selected={selected}
category={category.name}
categoryCount={category.count}
/>
)
})}
</div>
</div>
</div>
)
}
export default CategoryGroup

View File

@@ -1,3 +1,4 @@
import { useGlobal } from '@/lib/global'
import TagItemMini from './TagItemMini'
/**
@@ -8,17 +9,19 @@ import TagItemMini from './TagItemMini'
* @constructor
*/
const TagGroups = ({ tagOptions, currentTag }) => {
const { locale } = useGlobal()
if (!tagOptions) return <></>
return (
<div id='tags-group' className='dark:border-gray-600 py-4'>
<div className='mb-2'><i className='mr-2 fas fa-tag' />标签</div>
<div className='mb-2'>
<i className='mr-2 fas fa-tag' />
{locale.COMMON.TAGS}
</div>
<div className='space-y-2'>
{
tagOptions?.map(tag => {
const selected = tag.name === currentTag
return <TagItemMini key={tag.name} tag={tag} selected={selected} />
})
}
{tagOptions?.map(tag => {
const selected = tag.name === currentTag
return <TagItemMini key={tag.name} tag={tag} selected={selected} />
})}
</div>
</div>
)

View File

@@ -1,39 +1,39 @@
import CONFIG from './config'
import { useState, createContext, useContext, useEffect } from 'react'
import Footer from './components/Footer'
import InfoCard from './components/InfoCard'
import RevolverMaps from './components/RevolverMaps'
import Tabs from '@/components/Tabs'
import TopNavBar from './components/TopNavBar'
import SearchInput from './components/SearchInput'
import BottomMenuBar from './components/BottomMenuBar'
import { useGlobal } from '@/lib/global'
import { useRouter } from 'next/router'
import Comment from '@/components/Comment'
import Live2D from '@/components/Live2D'
import Announcement from './components/Announcement'
import JumpToTopButton from './components/JumpToTopButton'
import BlogPostListPage from './components/BlogPostListPage'
import BlogPostListScroll from './components/BlogPostListScroll'
import Catalog from './components/Catalog'
import { ArticleLock } from './components/ArticleLock'
import TagGroups from './components/TagGroups'
import CategoryGroup from './components/CategoryGroup'
import replaceSearchResult from '@/components/Mark'
import NotionPage from '@/components/NotionPage'
import ShareBar from '@/components/ShareBar'
import Tabs from '@/components/Tabs'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { isBrowser } from '@/lib/utils'
import { Transition } from '@headlessui/react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { createContext, useContext, useEffect, useState } from 'react'
import Announcement from './components/Announcement'
import ArticleAround from './components/ArticleAround'
import ArticleInfo from './components/ArticleInfo'
import { ArticleLock } from './components/ArticleLock'
import BlogArchiveItem from './components/BlogArchiveItem'
import BlogPostBar from './components/BlogPostBar'
import NotionPage from '@/components/NotionPage'
import Comment from '@/components/Comment'
import ArticleAround from './components/ArticleAround'
import TocDrawer from './components/TocDrawer'
import BlogPostListPage from './components/BlogPostListPage'
import BlogPostListScroll from './components/BlogPostListScroll'
import BottomMenuBar from './components/BottomMenuBar'
import Catalog from './components/Catalog'
import CategoryGroup from './components/CategoryGroup'
import CategoryItem from './components/CategoryItem'
import Footer from './components/Footer'
import InfoCard from './components/InfoCard'
import JumpToTopButton from './components/JumpToTopButton'
import RevolverMaps from './components/RevolverMaps'
import SearchInput from './components/SearchInput'
import TagGroups from './components/TagGroups'
import TagItemMini from './components/TagItemMini'
import ShareBar from '@/components/ShareBar'
import Link from 'next/link'
import { Transition } from '@headlessui/react'
import TocDrawer from './components/TocDrawer'
import TopNavBar from './components/TopNavBar'
import CONFIG from './config'
import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
import ArticleInfo from './components/ArticleInfo'
import { siteConfig } from '@/lib/config'
// 主题全局状态
const ThemeGlobalMedium = createContext()
@@ -51,86 +51,96 @@ const LayoutBase = props => {
const router = useRouter()
const [tocVisible, changeTocVisible] = useState(false)
const { onLoading, fullWidth } = useGlobal()
const [slotRight, setSlotRight] = useState(null);
const [slotRight, setSlotRight] = useState(null)
useEffect(()=> {
useEffect(() => {
if (post?.toc?.length > 0) {
setSlotRight(
<div key={locale.COMMON.TABLE_OF_CONTENTS}>
<Catalog toc={post?.toc} />
</div>
);
)
} else {
setSlotRight(null);
setSlotRight(null)
}
},[post])
}, [post])
const slotTop = <BlogPostBar {...props} />
return (
<ThemeGlobalMedium.Provider value={{ tocVisible, changeTocVisible }}>
{/* CSS样式 */}
<Style />
<ThemeGlobalMedium.Provider value={{ tocVisible, changeTocVisible }}>
{/* CSS样式 */}
<Style />
<div id='theme-medium' className={`${siteConfig('FONT_STYLE')} bg-white dark:bg-hexo-black-gray w-full h-full min-h-screen justify-center dark:text-gray-300 scroll-smooth`}>
<div
id='theme-medium'
className={`${siteConfig('FONT_STYLE')} bg-white dark:bg-hexo-black-gray w-full h-full min-h-screen justify-center dark:text-gray-300 scroll-smooth`}>
<main
id='wrapper'
className={
(JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE'))
? 'flex-row-reverse'
: '') + 'relative flex justify-between w-full h-full mx-auto'
}>
{/* 桌面端左侧菜单 */}
{/* <LeftMenuBar/> */}
<main id='wrapper' className={(JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE')) ? 'flex-row-reverse' : '') + 'relative flex justify-between w-full h-full mx-auto'}>
{/* 桌面端左侧菜单 */}
{/* <LeftMenuBar/> */}
{/* 主区 */}
<div id='container-wrapper' className='w-full relative z-10'>
{/* 顶部导航栏 */}
<TopNavBar {...props} />
{/* 主区 */}
<div id='container-wrapper' className='w-full relative z-10'>
<div
id='container-inner'
className={`px-7 ${fullWidth ? '' : 'max-w-5xl'} justify-center mx-auto min-h-screen`}>
<Transition
show={!onLoading}
appear={true}
enter='transition ease-in-out duration-700 transform order-first'
enterFrom='opacity-0 translate-y-16'
enterTo='opacity-100'
leave='transition ease-in-out duration-300 transform'
leaveFrom='opacity-100'
leaveTo='opacity-0 -translate-y-16'
unmount={false}>
{slotTop}
{children}
</Transition>
{/* 顶部导航栏 */}
<TopNavBar {...props} />
<div id='container-inner' className={`px-7 ${fullWidth ? '' : 'max-w-5xl'} justify-center mx-auto min-h-screen`}>
<Transition
show={!onLoading}
appear={true}
enter="transition ease-in-out duration-700 transform order-first"
enterFrom="opacity-0 translate-y-16"
enterTo="opacity-100"
leave="transition ease-in-out duration-300 transform"
leaveFrom="opacity-100"
leaveTo="opacity-0 -translate-y-16"
unmount={false}
>
{slotTop}
{children}
</Transition>
<JumpToTopButton />
</div>
{/* 底部 */}
<Footer title={siteConfig('TITLE')} />
</div>
{/* 桌面端右侧 */}
{fullWidth
? null
: <div className={`hidden xl:block border-l dark:border-transparent w-80 flex-shrink-0 relative z-10 ${siteConfig('MEDIUM_RIGHT_PANEL_DARK', null, CONFIG) ? 'bg-hexo-black-gray dark' : ''}`}>
<div className='py-14 px-6 sticky top-0'>
<Tabs>
{slotRight}
<div key={locale.NAV.ABOUT}>
{router.pathname !== '/search' && <SearchInput className='mt-6 mb-12' />}
{showInfoCard && <InfoCard {...props} />}
{siteConfig('MEDIUM_WIDGET_REVOLVER_MAPS', null, CONFIG) === 'true' && <RevolverMaps />}
</div>
</Tabs>
<Announcement post={notice} />
<Live2D />
</div>
</div>}
</main>
{/* 移动端底部导航栏 */}
<BottomMenuBar {...props} className='block md:hidden' />
<JumpToTopButton />
</div>
</ThemeGlobalMedium.Provider>
{/* 底部 */}
<Footer title={siteConfig('TITLE')} />
</div>
{/* 桌面端右侧 */}
{fullWidth ? null : (
<div
className={`hidden xl:block border-l dark:border-transparent w-80 flex-shrink-0 relative z-10 ${siteConfig('MEDIUM_RIGHT_PANEL_DARK', null, CONFIG) ? 'bg-hexo-black-gray dark' : ''}`}>
<div className='py-14 px-6 sticky top-0'>
<Tabs>
{slotRight}
<div key={locale.NAV.ABOUT}>
{router.pathname !== '/search' && (
<SearchInput className='mt-6 mb-12' />
)}
{showInfoCard && <InfoCard {...props} />}
{siteConfig('MEDIUM_WIDGET_REVOLVER_MAPS', null, CONFIG) ===
'true' && <RevolverMaps />}
</div>
</Tabs>
<Announcement post={notice} />
<Live2D />
</div>
</div>
)}
</main>
{/* 移动端底部导航栏 */}
<BottomMenuBar {...props} className='block md:hidden' />
</div>
</ThemeGlobalMedium.Provider>
)
}
@@ -140,7 +150,7 @@ const LayoutBase = props => {
* @param {*} props
* @returns
*/
const LayoutIndex = (props) => {
const LayoutIndex = props => {
return <LayoutPostList {...props} />
}
@@ -148,10 +158,16 @@ const LayoutIndex = (props) => {
* 博客列表
* @returns
*/
const LayoutPostList = (props) => {
return <>
{siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
const LayoutPostList = props => {
return (
<>
{siteConfig('POST_LIST_STYLE') === 'page' ? (
<BlogPostListPage {...props} />
) : (
<BlogPostListScroll {...props} />
)}
</>
)
}
/**
@@ -163,64 +179,72 @@ const LayoutSlug = props => {
const { post, prev, next, lock, validPassword } = props
const { locale } = useGlobal()
const slotRight = post?.toc && post?.toc?.length >= 3 && (
<div key={locale.COMMON.TABLE_OF_CONTENTS} >
<Catalog toc={post?.toc} />
</div>
<div key={locale.COMMON.TABLE_OF_CONTENTS}>
<Catalog toc={post?.toc} />
</div>
)
const router = useRouter()
useEffect(() => {
// 404
if (!post) {
setTimeout(() => {
if (isBrowser) {
const article = document.getElementById('notion-article')
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
setTimeout(
() => {
if (isBrowser) {
const article = document.getElementById('notion-article')
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
}
}
}
}, siteConfig('POST_WAITING_TIME_FOR_404') * 1000)
},
siteConfig('POST_WAITING_TIME_FOR_404') * 1000
)
}
}, [post])
return (
<div {...props} >
{/* 文章锁 */}
{lock && <ArticleLock validPassword={validPassword} />}
<div {...props}>
{/* 文章锁 */}
{lock && <ArticleLock validPassword={validPassword} />}
{!lock && <div id='article-wrapper'>
{!lock && (
<div>
{/* 文章信息 */}
<ArticleInfo {...props} />
{/* 文章信息 */}
<ArticleInfo {...props} />
{/* Notion文章主体 */}
<article id='article-wrapper' className='px-1 max-w-4xl'>
{post && <NotionPage post={post} />}
</article>
{/* Notion文章主体 */}
<section className="px-1 max-w-4xl">
{post && (<NotionPage post={post} />)}
</section>
{/* 文章底部区域 */}
<section>
{/* 分享 */}
<ShareBar post={post} />
{/* 文章分类和标签信息 */}
<div className='flex justify-between'>
{siteConfig('MEDIUM_POST_DETAIL_CATEGORY', null, CONFIG) &&
post?.category && <CategoryItem category={post?.category} />}
<div>
{siteConfig('MEDIUM_POST_DETAIL_TAG', null, CONFIG) &&
post?.tagItems?.map(tag => (
<TagItemMini key={tag.name} tag={tag} />
))}
</div>
</div>
{/* 上一篇下一篇文章 */}
{post?.type === 'Post' && <ArticleAround prev={prev} next={next} />}
{/* 评论区 */}
<Comment frontMatter={post} />
</section>
{/* 文章底部区域 */}
<section>
{/* 分享 */}
<ShareBar post={post} />
{/* 文章分类和标签信息 */}
<div className='flex justify-between'>
{siteConfig('MEDIUM_POST_DETAIL_CATEGORY', null, CONFIG) && post?.category && <CategoryItem category={post?.category} />}
<div>
{siteConfig('MEDIUM_POST_DETAIL_TAG', null, CONFIG) && post?.tagItems?.map(tag => <TagItemMini key={tag.name} tag={tag} />)}
</div>
</div>
{/* 上一篇下一篇文章 */}
{post?.type === 'Post' && <ArticleAround prev={prev} next={next} />}
{/* 评论区 */}
<Comment frontMatter={post} />
</section>
{/* 移动端目录 */}
<TocDrawer {...props} />
</div>}
{/* 移动端目录 */}
<TocDrawer {...props} />
</div>
)}
</div>
)
}
@@ -229,7 +253,7 @@ const LayoutSlug = props => {
* @param {*} props
* @returns
*/
const LayoutSearch = (props) => {
const LayoutSearch = props => {
const { locale } = useGlobal()
const { keyword } = props
const router = useRouter()
@@ -248,23 +272,32 @@ const LayoutSearch = (props) => {
}
}, [])
return <>
return (
<>
{/* 搜索导航栏 */}
<div className='py-12'>
<div className='pb-4 w-full'>{locale.NAV.SEARCH}</div>
<SearchInput currentSearch={currentSearch} {...props} />
{!currentSearch && (
<>
<TagGroups {...props} />
<CategoryGroup {...props} />
</>
)}
</div>
{/* 搜索导航栏 */}
<div className='py-12'>
<div className='pb-4 w-full'>{locale.NAV.SEARCH}</div>
<SearchInput currentSearch={currentSearch} {...props} />
{!currentSearch && <>
<TagGroups {...props} />
<CategoryGroup {...props} />
</>}
{/* 文章列表 */}
{currentSearch && (
<div>
{siteConfig('POST_LIST_STYLE') === 'page' ? (
<BlogPostListPage {...props} />
) : (
<BlogPostListScroll {...props} />
)}
</div>
{/* 文章列表 */}
{currentSearch && <div>
{siteConfig('POST_LIST_STYLE') === 'page' ? <BlogPostListPage {...props} /> : <BlogPostListScroll {...props} />}
</div>}
)}
</>
)
}
/**
@@ -275,12 +308,17 @@ const LayoutSearch = (props) => {
const LayoutArchive = props => {
const { archivePosts } = props
return (
<>
<div className="mb-10 pb-20 md:py-12 py-3 min-h-full">
{Object.keys(archivePosts)?.map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />
)}
</div>
</>
<>
<div className='mb-10 pb-20 md:py-12 py-3 min-h-full'>
{Object.keys(archivePosts)?.map(archiveTitle => (
<BlogArchiveItem
key={archiveTitle}
archiveTitle={archiveTitle}
archivePosts={archivePosts}
/>
))}
</div>
</>
)
}
@@ -290,9 +328,13 @@ const LayoutArchive = props => {
* @returns
*/
const Layout404 = props => {
return <>
<div className='w-full h-96 py-80 flex justify-center items-center'>404 Not found.</div>
return (
<>
<div className='w-full h-96 py-80 flex justify-center items-center'>
404 Not found.
</div>
</>
)
}
/**
@@ -300,33 +342,37 @@ const Layout404 = props => {
* @param {*} props
* @returns
*/
const LayoutCategoryIndex = (props) => {
const LayoutCategoryIndex = props => {
const { categoryOptions } = props
const { locale } = useGlobal()
return (
<>
<div className='bg-white dark:bg-gray-700 py-10'>
<div className='dark:text-gray-200 mb-5'>
<i className='mr-4 fas fa-th' />{locale.COMMON.CATEGORY}:
<>
<div className='bg-white dark:bg-gray-700 py-10'>
<div className='dark:text-gray-200 mb-5'>
<i className='mr-4 fas fa-th' />
{locale.COMMON.CATEGORY}:
</div>
<div id='category-list' className='duration-200 flex flex-wrap'>
{categoryOptions?.map(category => {
return (
<Link
key={category.name}
href={`/category/${category.name}`}
passHref
legacyBehavior>
<div
className={
'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'
}>
<i className='mr-4 fas fa-folder' />
{category.name}({category.count})
</div>
<div id='category-list' className='duration-200 flex flex-wrap'>
{categoryOptions?.map(category => {
return (
<Link
key={category.name}
href={`/category/${category.name}`}
passHref
legacyBehavior>
<div
className={'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'}>
<i className='mr-4 fas fa-folder' />{category.name}({category.count})
</div>
</Link>
)
})}
</div>
</div>
</>
</Link>
)
})}
</div>
</div>
</>
)
}
@@ -339,35 +385,35 @@ const LayoutTagIndex = props => {
const { tagOptions } = props
const { locale } = useGlobal()
return (
<>
<div className="bg-white dark:bg-gray-700 py-10">
<div className="dark:text-gray-200 mb-5">
<i className="mr-4 fas fa-tag" />
{locale.COMMON.TAGS}:
</div>
<div id="tags-list" className="duration-200 flex flex-wrap">
{tagOptions?.map(tag => {
return (
<div key={tag.name} className="p-2">
<TagItemMini key={tag.name} tag={tag} />
</div>
)
})}
</div>
</div>
</>
<>
<div className='bg-white dark:bg-gray-700 py-10'>
<div className='dark:text-gray-200 mb-5'>
<i className='mr-4 fas fa-tag' />
{locale.COMMON.TAGS}:
</div>
<div id='tags-list' className='duration-200 flex flex-wrap'>
{tagOptions?.map(tag => {
return (
<div key={tag.name} className='p-2'>
<TagItemMini key={tag.name} tag={tag} />
</div>
)
})}
</div>
</div>
</>
)
}
export {
CONFIG as THEME_CONFIG,
Layout404,
LayoutArchive,
LayoutBase,
LayoutCategoryIndex,
LayoutIndex,
LayoutPostList,
LayoutSearch,
LayoutArchive,
LayoutSlug,
Layout404,
LayoutCategoryIndex,
LayoutTagIndex
LayoutTagIndex,
CONFIG as THEME_CONFIG
}

View File

@@ -258,7 +258,11 @@ const LayoutSlug = props => {
videoWrapper.appendChild(figCaptionWrapper)
}
// 放入页面
notionArticle.insertBefore(videoWrapper, notionArticle.firstChild)
if (notionArticle.firstChild && notionArticle.contains(notionArticle.firstChild)) {
notionArticle.insertBefore(videoWrapper, notionArticle.firstChild)
} else {
notionArticle.appendChild(videoWrapper)
}
}
}

View File

@@ -290,8 +290,10 @@ const LayoutSlug = props => {
{/* Notion文章主体 */}
{post && (
<section id='article-wrapper' className='px-1'>
<NotionPage post={post} />
<section className='px-1'>
<div id='article-wrapper'>
<NotionPage post={post} />
</div>
{/* 分享 */}
{/* <ShareBar post={post} /> */}

View File

@@ -35,9 +35,7 @@ export default function ArticleDetail(props) {
}
return (
<div
id='article-wrapper'
className='shadow md:hover:shadow-2xl overflow-x-auto flex-grow mx-auto w-screen md:w-full '>
<div className='shadow md:hover:shadow-2xl overflow-x-auto flex-grow mx-auto w-screen md:w-full '>
<div
itemScope
itemType='https://schema.org/Movie'
@@ -100,7 +98,7 @@ export default function ArticleDetail(props) {
)}
{/* Notion内容主体 */}
<article className='mx-auto'>
<article id='article-wrapper' className='mx-auto'>
<WWAds className='w-full' orientation='horizontal' />
{post && <NotionPage post={post} />}
<WWAds className='w-full' orientation='horizontal' />

View File

@@ -1,34 +1,37 @@
import CONFIG from './config'
import replaceSearchResult from '@/components/Mark'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { isBrowser } from '@/lib/utils'
import dynamic from 'next/dynamic'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { createContext, useContext, useEffect, useRef, useState } from 'react'
import Announcement from './components/Announcement'
import ArticleDetail from './components/ArticleDetail'
import { ArticleLock } from './components/ArticleLock'
import BlogListBar from './components/BlogListBar'
import BlogPostArchive from './components/BlogPostArchive'
import BlogPostListPage from './components/BlogPostListPage'
import BlogPostListScroll from './components/BlogPostListScroll'
import Card from './components/Card'
import FloatDarkModeButton from './components/FloatDarkModeButton'
import Footer from './components/Footer'
import JumpToBottomButton from './components/JumpToBottomButton'
import JumpToTopButton from './components/JumpToTopButton'
import SideAreaLeft from './components/SideAreaLeft'
import SideAreaRight from './components/SideAreaRight'
import TopNav from './components/TopNav'
import { useGlobal } from '@/lib/global'
import { createContext, useContext, useEffect, useRef, useState } from 'react'
import BlogPostListScroll from './components/BlogPostListScroll'
import BlogPostListPage from './components/BlogPostListPage'
import StickyBar from './components/StickyBar'
import { isBrowser } from '@/lib/utils'
import TocDrawerButton from './components/TocDrawerButton'
import TocDrawer from './components/TocDrawer'
import { ArticleLock } from './components/ArticleLock'
import BlogPostArchive from './components/BlogPostArchive'
import TagItem from './components/TagItem'
import { useRouter } from 'next/router'
import ArticleDetail from './components/ArticleDetail'
import Link from 'next/link'
import BlogListBar from './components/BlogListBar'
import TocDrawer from './components/TocDrawer'
import TocDrawerButton from './components/TocDrawerButton'
import TopNav from './components/TopNav'
import CONFIG from './config'
import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
import { siteConfig } from '@/lib/config'
import Announcement from './components/Announcement'
import Card from './components/Card'
import dynamic from 'next/dynamic'
const AlgoliaSearchModal = dynamic(() => import('@/components/AlgoliaSearchModal'), { ssr: false })
const AlgoliaSearchModal = dynamic(
() => import('@/components/AlgoliaSearchModal'),
{ ssr: false }
)
// 主题全局状态
const ThemeGlobalNext = createContext()
@@ -39,7 +42,7 @@ export const useNextGlobal = () => useContext(ThemeGlobalNext)
* @returns {JSX.Element}
* @constructor
*/
const LayoutBase = (props) => {
const LayoutBase = props => {
const { children, headerSlot, rightAreaSlot, post } = props
const targetRef = useRef(null)
const floatButtonGroup = useRef(null)
@@ -50,7 +53,7 @@ const LayoutBase = (props) => {
const clientHeight = targetRef?.clientHeight
const scrollY = window.pageYOffset
const fullHeight = clientHeight - window.outerHeight
let per = parseFloat(((scrollY / fullHeight * 100)).toFixed(0))
let per = parseFloat(((scrollY / fullHeight) * 100).toFixed(0))
if (per > 100) per = 100
const shouldShow = scrollY > 100 && per > 0
@@ -75,11 +78,15 @@ const LayoutBase = (props) => {
// 悬浮抽屉
const drawerRight = useRef(null)
const floatSlot = <div className='block lg:hidden'>
<TocDrawerButton onClick={() => {
drawerRight?.current?.handleSwitchVisible()
}} />
</div>
const floatSlot = (
<div className='block lg:hidden'>
<TocDrawerButton
onClick={() => {
drawerRight?.current?.handleSwitchVisible()
}}
/>
</div>
)
const tocRef = isBrowser ? document.getElementById('article-wrapper') : null
@@ -87,53 +94,77 @@ const LayoutBase = (props) => {
return (
<ThemeGlobalNext.Provider value={{ searchModal }}>
<div id='theme-next' className={`${siteConfig('FONT_STYLE')} dark:bg-black scroll-smooth`}>
<Style/>
<div
id='theme-next'
className={`${siteConfig('FONT_STYLE')} dark:bg-black scroll-smooth`}>
<Style />
{/* 移动端顶部导航栏 */}
<TopNav {...props} />
{/* 移动端顶部导航栏 */}
<TopNav {...props} />
<AlgoliaSearchModal cRef={searchModal} {...props}/>
<AlgoliaSearchModal cRef={searchModal} {...props} />
<>{headerSlot}</>
<>{headerSlot}</>
{/* 顶部黑线装饰 */}
<div className='h-0.5 w-full bg-gray-700 dark:bg-gray-600 hidden lg:block' />
{/* 顶部黑线装饰 */}
<div className='h-0.5 w-full bg-gray-700 dark:bg-gray-600 hidden lg:block' />
{/* 主区 */}
<main id='wrapper' className={(JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE')) ? 'flex-row-reverse' : '') + ' next relative flex justify-center flex-1 pb-12'}>
{/* 左侧栏样式 */}
<SideAreaLeft targetRef={targetRef} {...props} />
{/* 主区 */}
<main
id='wrapper'
className={
(JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE'))
? 'flex-row-reverse'
: '') + ' next relative flex justify-center flex-1 pb-12'
}>
{/* 左侧栏样式 */}
<SideAreaLeft targetRef={targetRef} {...props} />
{/* 中央内容 */}
<section id='container-inner' className={`${siteConfig('NEXT_NAV_TYPE', null, CONFIG) !== 'normal' ? 'mt-24' : ''} lg:max-w-3xl xl:max-w-4xl flex-grow md:mt-0 min-h-screen w-full relative z-10`} ref={targetRef}>
{children}
</section>
{/* 中央内容 */}
<section
id='container-inner'
className={`${siteConfig('NEXT_NAV_TYPE', null, CONFIG) !== 'normal' ? 'mt-24' : ''} lg:max-w-3xl xl:max-w-4xl flex-grow md:mt-0 min-h-screen w-full relative z-10`}
ref={targetRef}>
{children}
</section>
{/* 右侧栏样式 */}
{siteConfig('NEXT_RIGHT_BAR', null, CONFIG) && <SideAreaRight targetRef={targetRef} slot={rightAreaSlot} {...props} />}
{/* 右侧栏样式 */}
{siteConfig('NEXT_RIGHT_BAR', null, CONFIG) && (
<SideAreaRight
targetRef={targetRef}
slot={rightAreaSlot}
{...props}
/>
)}
</main>
</main>
{/* 悬浮目录按钮 */}
{post && (
<div className='block lg:hidden'>
<TocDrawer post={post} cRef={drawerRight} targetRef={tocRef} />
</div>
)}
{/* 悬浮目录按钮 */}
{post && <div className='block lg:hidden'>
<TocDrawer post={post} cRef={drawerRight} targetRef={tocRef} />
</div>}
{/* 右下角悬浮 */}
<div ref={floatButtonGroup} className='right-8 bottom-12 lg:right-2 fixed justify-end z-20 '>
<div className={(showRightFloat ? 'animate__animated ' : 'hidden') + ' animate__fadeInUp rounded-md glassmorphism justify-center duration-500 animate__faster flex space-x-2 items-center cursor-pointer '}>
<JumpToTopButton percent={percent} />
<JumpToBottomButton />
<FloatDarkModeButton />
{floatSlot}
</div>
</div>
{/* 页脚 */}
<Footer title={siteConfig('TITLE')} />
{/* 右下角悬浮 */}
<div
ref={floatButtonGroup}
className='right-8 bottom-12 lg:right-2 fixed justify-end z-20 '>
<div
className={
(showRightFloat ? 'animate__animated ' : 'hidden') +
' animate__fadeInUp rounded-md glassmorphism justify-center duration-500 animate__faster flex space-x-2 items-center cursor-pointer '
}>
<JumpToTopButton percent={percent} />
<JumpToBottomButton />
<FloatDarkModeButton />
{floatSlot}
</div>
</div>
</ThemeGlobalNext.Provider>
{/* 页脚 */}
<Footer title={siteConfig('TITLE')} />
</div>
</ThemeGlobalNext.Provider>
)
}
@@ -143,21 +174,24 @@ const LayoutBase = (props) => {
* @param {*} props
* @returns
*/
const LayoutIndex = (props) => {
const LayoutIndex = props => {
const { notice } = props
return <>
{/* 首页移动端顶部显示公告 */}
<Card className='my-2 lg:hidden'>
<Announcement post={notice} />
</Card>
return (
<>
{/* 首页移动端顶部显示公告 */}
<Card className='my-2 lg:hidden'>
<Announcement post={notice} />
</Card>
<BlogListBar {...props} />
<BlogListBar {...props} />
{siteConfig('POST_LIST_STYLE') !== 'page'
? <BlogPostListScroll {...props} showSummary={true} />
: <BlogPostListPage {...props} />
}
{siteConfig('POST_LIST_STYLE') !== 'page' ? (
<BlogPostListScroll {...props} showSummary={true} />
) : (
<BlogPostListPage {...props} />
)}
</>
)
}
/**
@@ -165,16 +199,18 @@ const LayoutIndex = (props) => {
* @param {*} props
* @returns
*/
const LayoutPostList = (props) => {
return <>
const LayoutPostList = props => {
return (
<>
<BlogListBar {...props} />
<BlogListBar {...props} />
{siteConfig('POST_LIST_STYLE') !== 'page'
? <BlogPostListScroll {...props} showSummary={true} />
: <BlogPostListPage {...props} />
}
{siteConfig('POST_LIST_STYLE') !== 'page' ? (
<BlogPostListScroll {...props} showSummary={true} />
) : (
<BlogPostListPage {...props} />
)}
</>
)
}
/**
@@ -182,7 +218,7 @@ const LayoutPostList = (props) => {
* @param {*} props
* @returns
*/
const LayoutSearch = (props) => {
const LayoutSearch = props => {
const { locale } = useGlobal()
const { posts, keyword } = props
@@ -200,20 +236,21 @@ const LayoutSearch = (props) => {
}, [])
return (
<>
<StickyBar>
<div className="p-4 dark:text-gray-200">
<i className="mr-1 fas fa-search" />{' '}
{posts?.length} {locale.COMMON.RESULT_OF_SEARCH}
</div>
</StickyBar>
<div className="md:mt-5">
{siteConfig('POST_LIST_STYLE') !== 'page'
? <BlogPostListScroll {...props} showSummary={true} />
: <BlogPostListPage {...props} />
}
</div>
</>
<>
<StickyBar>
<div className='p-4 dark:text-gray-200'>
<i className='mr-1 fas fa-search' /> {posts?.length}{' '}
{locale.COMMON.RESULT_OF_SEARCH}
</div>
</StickyBar>
<div className='md:mt-5'>
{siteConfig('POST_LIST_STYLE') !== 'page' ? (
<BlogPostListScroll {...props} showSummary={true} />
) : (
<BlogPostListPage {...props} />
)}
</div>
</>
)
}
@@ -236,16 +273,21 @@ const Layout404 = props => {
}, 3000)
}, [])
return <>
<div className='md:-mt-20 text-black w-full h-screen text-center justify-center content-center items-center flex flex-col'>
<div className='dark:text-gray-200'>
<h2 className='inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top'><i className='mr-2 fas fa-spinner animate-spin' />404</h2>
<div className='inline-block text-left h-32 leading-10 items-center'>
<h2 className='m-0 p-0'>页面无法加载即将返回首页</h2>
</div>
</div>
return (
<>
<div className='md:-mt-20 text-black w-full h-screen text-center justify-center content-center items-center flex flex-col'>
<div className='dark:text-gray-200'>
<h2 className='inline-block border-r-2 border-gray-600 mr-2 px-3 py-2 align-top'>
<i className='mr-2 fas fa-spinner animate-spin' />
404
</h2>
<div className='inline-block text-left h-32 leading-10 items-center'>
<h2 className='m-0 p-0'>页面无法加载即将返回首页</h2>
</div>
</div>
</div>
</>
)
}
/**
@@ -253,21 +295,21 @@ const Layout404 = props => {
* @param {*} props
* @returns
*/
const LayoutArchive = (props) => {
const LayoutArchive = props => {
const { archivePosts } = props
return (
<>
<div className="mb-10 pb-20 bg-white md:p-12 p-3 dark:bg-hexo-black-gray shadow-md min-h-full">
{Object.keys(archivePosts).map(archiveTitle => (
<BlogPostArchive
key={archiveTitle}
posts={archivePosts[archiveTitle]}
archiveTitle={archiveTitle}
/>
))}
</div>
</>
<>
<div className='mb-10 pb-20 bg-white md:p-12 p-3 dark:bg-hexo-black-gray shadow-md min-h-full'>
{Object.keys(archivePosts).map(archiveTitle => (
<BlogPostArchive
key={archiveTitle}
posts={archivePosts[archiveTitle]}
archiveTitle={archiveTitle}
/>
))}
</div>
</>
)
}
@@ -276,33 +318,34 @@ const LayoutArchive = (props) => {
* @param {*} props
* @returns
*/
const LayoutSlug = (props) => {
const LayoutSlug = props => {
const { post, lock, validPassword } = props
const router = useRouter()
useEffect(() => {
// 404
if (!post) {
setTimeout(() => {
if (isBrowser) {
const article = document.getElementById('notion-article')
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
setTimeout(
() => {
if (isBrowser) {
const article = document.getElementById('notion-article')
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
}
}
}
}, siteConfig('POST_WAITING_TIME_FOR_404') * 1000)
},
siteConfig('POST_WAITING_TIME_FOR_404') * 1000
)
}
}, [post])
return (
<>
<>
{post && !lock && <ArticleDetail {...props} />}
{post && !lock && <ArticleDetail {...props} />}
{post && lock && <ArticleLock validPassword={validPassword} />}
</>
{post && lock && <ArticleLock validPassword={validPassword} />}
</>
)
}
@@ -311,33 +354,37 @@ const LayoutSlug = (props) => {
* @param {*} props
* @returns
*/
const LayoutCategoryIndex = (props) => {
const LayoutCategoryIndex = props => {
const { allPosts, categoryOptions } = props
const { locale } = useGlobal()
return (
<div totalPosts={allPosts} {...props}>
<div className='bg-white dark:bg-hexo-black-gray px-10 py-10 shadow h-full'>
<div className='dark:text-gray-200 mb-5'>
<i className='mr-4 fas faTh' />{locale.COMMON.CATEGORY}:
</div>
<div id='category-list' className='duration-200 flex flex-wrap'>
{categoryOptions?.map(category => {
return (
<Link
key={category.name}
href={`/category/${category.name}`}
passHref
legacyBehavior>
<div
className={'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'}>
<i className='mr-4 fas fa-folder' />{category.name}({category.count})
</div>
</Link>
)
})}
</div>
</div>
<div totalPosts={allPosts} {...props}>
<div className='bg-white dark:bg-hexo-black-gray px-10 py-10 shadow h-full'>
<div className='dark:text-gray-200 mb-5'>
<i className='mr-4 fas faTh' />
{locale.COMMON.CATEGORY}:
</div>
<div id='category-list' className='duration-200 flex flex-wrap'>
{categoryOptions?.map(category => {
return (
<Link
key={category.name}
href={`/category/${category.name}`}
passHref
legacyBehavior>
<div
className={
'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'
}>
<i className='mr-4 fas fa-folder' />
{category.name}({category.count})
</div>
</Link>
)
})}
</div>
</div>
</div>
)
}
@@ -346,30 +393,39 @@ const LayoutCategoryIndex = (props) => {
* @param {*} props
* @returns
*/
const LayoutTagIndex = (props) => {
const LayoutTagIndex = props => {
const { tagOptions } = props
const { locale } = useGlobal()
return <>
<div className='bg-white dark:bg-hexo-black-gray px-10 py-10 shadow h-full'>
<div className='dark:text-gray-200 mb-5'><i className='fas fa-tags mr-4' />{locale.COMMON.TAGS}:</div>
<div id='tags-list' className='duration-200 flex flex-wrap'>
{tagOptions.map(tag => {
return <div key={tag.name} className='p-2'><TagItem key={tag.name} tag={tag} /></div>
})}
</div>
return (
<>
<div className='bg-white dark:bg-hexo-black-gray px-10 py-10 shadow h-full'>
<div className='dark:text-gray-200 mb-5'>
<i className='fas fa-tags mr-4' />
{locale.COMMON.TAGS}:
</div>
<div id='tags-list' className='duration-200 flex flex-wrap'>
{tagOptions.map(tag => {
return (
<div key={tag.name} className='p-2'>
<TagItem key={tag.name} tag={tag} />
</div>
)
})}
</div>
</div>
</>
)
}
export {
CONFIG as THEME_CONFIG,
LayoutBase,
LayoutIndex,
LayoutSearch,
LayoutArchive,
LayoutSlug,
Layout404,
LayoutArchive,
LayoutBase,
LayoutCategoryIndex,
LayoutIndex,
LayoutPostList,
LayoutTagIndex
LayoutSearch,
LayoutSlug,
LayoutTagIndex,
CONFIG as THEME_CONFIG
}

View File

@@ -1,32 +1,35 @@
import CONFIG from './config'
import { createContext, useEffect, useState, useContext, useRef } from 'react'
import Nav from './components/Nav'
import { Footer } from './components/Footer'
import JumpToTopButton from './components/JumpToTopButton'
import Comment from '@/components/Comment'
import Live2D from '@/components/Live2D'
import replaceSearchResult from '@/components/Mark'
import NotionPage from '@/components/NotionPage'
import ShareBar from '@/components/ShareBar'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { deepClone, isBrowser } from '@/lib/utils'
import { Transition } from '@headlessui/react'
import dynamic from 'next/dynamic'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { createContext, useContext, useEffect, useRef, useState } from 'react'
import Announcement from './components/Announcement'
import { ArticleFooter } from './components/ArticleFooter'
import { ArticleInfo } from './components/ArticleInfo'
import { ArticleLock } from './components/ArticleLock'
import BlogArchiveItem from './components/BlogArchiveItem'
import BlogListBar from './components/BlogListBar'
import { BlogListPage } from './components/BlogListPage'
import { BlogListScroll } from './components/BlogListScroll'
import { deepClone, isBrowser } from '@/lib/utils'
import { Footer } from './components/Footer'
import JumpToTopButton from './components/JumpToTopButton'
import Nav from './components/Nav'
import SearchNavBar from './components/SearchNavBar'
import BlogArchiveItem from './components/BlogArchiveItem'
import { ArticleLock } from './components/ArticleLock'
import NotionPage from '@/components/NotionPage'
import { ArticleInfo } from './components/ArticleInfo'
import Comment from '@/components/Comment'
import { ArticleFooter } from './components/ArticleFooter'
import ShareBar from '@/components/ShareBar'
import Link from 'next/link'
import BlogListBar from './components/BlogListBar'
import { Transition } from '@headlessui/react'
import CONFIG from './config'
import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
import { siteConfig } from '@/lib/config'
import { useRouter } from 'next/router'
import dynamic from 'next/dynamic'
const AlgoliaSearchModal = dynamic(() => import('@/components/AlgoliaSearchModal'), { ssr: false })
const AlgoliaSearchModal = dynamic(
() => import('@/components/AlgoliaSearchModal'),
{ ssr: false }
)
// 主题全局状态
const ThemeGlobalNobelium = createContext()
@@ -45,56 +48,56 @@ const LayoutBase = props => {
const searchModal = useRef(null)
// 在列表中进行实时过滤
const [filterKey, setFilterKey] = useState('')
const topSlot = <BlogListBar {...props}/>
const topSlot = <BlogListBar {...props} />
return (
<ThemeGlobalNobelium.Provider value={{ searchModal, filterKey, setFilterKey }}>
<div id='theme-nobelium' className={`${siteConfig('FONT_STYLE')} nobelium relative dark:text-gray-300 w-full bg-white dark:bg-black min-h-screen flex flex-col scroll-smooth`}>
<ThemeGlobalNobelium.Provider
value={{ searchModal, filterKey, setFilterKey }}>
<div
id='theme-nobelium'
className={`${siteConfig('FONT_STYLE')} nobelium relative dark:text-gray-300 w-full bg-white dark:bg-black min-h-screen flex flex-col scroll-smooth`}>
<Style />
<Style />
{/* 顶部导航栏 */}
<Nav {...props} />
{/* 顶部导航栏 */}
<Nav {...props} />
{/* 主区 */}
<main
id='out-wrapper'
className={`relative m-auto flex-grow w-full transition-all ${!fullWidth ? 'max-w-2xl px-4' : 'px-4 md:px-24'}`}>
<Transition
show={!onLoading}
appear={true}
enter='transition ease-in-out duration-700 transform order-first'
enterFrom='opacity-0 translate-y-16'
enterTo='opacity-100'
leave='transition ease-in-out duration-300 transform'
leaveFrom='opacity-100 translate-y-0'
leaveTo='opacity-0 -translate-y-16'
unmount={false}>
{/* 顶部插槽 */}
{topSlot}
{children}
</Transition>
</main>
{/* 主区 */}
<main id='out-wrapper' className={`relative m-auto flex-grow w-full transition-all ${!fullWidth ? 'max-w-2xl px-4' : 'px-4 md:px-24'}`}>
{/* 页脚 */}
<Footer {...props} />
<Transition
show={!onLoading}
appear={true}
enter="transition ease-in-out duration-700 transform order-first"
enterFrom="opacity-0 translate-y-16"
enterTo="opacity-100"
leave="transition ease-in-out duration-300 transform"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 -translate-y-16"
unmount={false}
>
{/* 顶部插槽 */}
{topSlot}
{children}
</Transition>
{/* 右下悬浮 */}
<div className='fixed right-4 bottom-4'>
<JumpToTopButton />
</div>
</main>
{/* 左下悬浮 */}
<div className='bottom-4 -left-14 fixed justify-end z-40'>
<Live2D />
</div>
{/* 页脚 */}
<Footer {...props} />
{/* 右下悬浮 */}
<div className='fixed right-4 bottom-4'>
<JumpToTopButton />
</div>
{/* 左下悬浮 */}
<div className="bottom-4 -left-14 fixed justify-end z-40">
<Live2D />
</div>
{/* 搜索框 */}
<AlgoliaSearchModal cRef={searchModal} {...props}/>
</div>
</ThemeGlobalNobelium.Provider>
{/* 搜索框 */}
<AlgoliaSearchModal cRef={searchModal} {...props} />
</div>
</ThemeGlobalNobelium.Provider>
)
}
@@ -105,9 +108,7 @@ const LayoutBase = props => {
* @returns
*/
const LayoutIndex = props => {
return (
<LayoutPostList {...props} topSlot={<Announcement {...props} />} />
)
return <LayoutPostList {...props} topSlot={<Announcement {...props} />} />
}
/**
@@ -130,11 +131,15 @@ const LayoutPostList = props => {
}
return (
<>
{topSlot}
{tag && <SearchNavBar {...props} />}
{siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} posts={filteredBlogPosts} /> : <BlogListScroll {...props} posts={filteredBlogPosts} />}
</>
<>
{topSlot}
{tag && <SearchNavBar {...props} />}
{siteConfig('POST_LIST_STYLE') === 'page' ? (
<BlogListPage {...props} posts={filteredBlogPosts} />
) : (
<BlogListScroll {...props} posts={filteredBlogPosts} />
)}
</>
)
}
@@ -172,10 +177,16 @@ const LayoutSearch = props => {
filteredBlogPosts = deepClone(posts)
}
return <>
<SearchNavBar {...props} />
{siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} posts={filteredBlogPosts} /> : <BlogListScroll {...props} posts={filteredBlogPosts} />}
</>
return (
<>
<SearchNavBar {...props} />
{siteConfig('POST_LIST_STYLE') === 'page' ? (
<BlogListPage {...props} posts={filteredBlogPosts} />
) : (
<BlogListScroll {...props} posts={filteredBlogPosts} />
)}
</>
)
}
/**
@@ -186,11 +197,17 @@ const LayoutSearch = props => {
const LayoutArchive = props => {
const { archivePosts } = props
return (
<>
<div className="mb-10 pb-20 md:py-12 p-3 min-h-screen w-full">
{Object.keys(archivePosts).map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />)}
</div>
</>
<>
<div className='mb-10 pb-20 md:py-12 p-3 min-h-screen w-full'>
{Object.keys(archivePosts).map(archiveTitle => (
<BlogArchiveItem
key={archiveTitle}
archiveTitle={archiveTitle}
archivePosts={archivePosts}
/>
))}
</div>
</>
)
}
@@ -205,34 +222,39 @@ const LayoutSlug = props => {
useEffect(() => {
// 404
if (!post) {
setTimeout(() => {
if (isBrowser) {
const article = document.getElementById('notion-article')
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
setTimeout(
() => {
if (isBrowser) {
const article = document.getElementById('notion-article')
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
}
}
}
}, siteConfig('POST_WAITING_TIME_FOR_404') * 1000)
},
siteConfig('POST_WAITING_TIME_FOR_404') * 1000
)
}
}, [post])
return (
<>
<>
{lock && <ArticleLock validPassword={validPassword} />}
{lock && <ArticleLock validPassword={validPassword} />}
{!lock && <div id="article-wrapper" className="px-2">
<>
<ArticleInfo post={post} />
<NotionPage post={post} />
<ShareBar post={post} />
<Comment frontMatter={post} />
<ArticleFooter />
</>
</div>}
</>
{!lock && (
<div className='px-2'>
<>
<ArticleInfo post={post} />
<div id='article-wrapper'>
<NotionPage post={post} />
</div>
<ShareBar post={post} />
<Comment frontMatter={post} />
<ArticleFooter />
</>
</div>
)}
</>
)
}
@@ -241,10 +263,8 @@ const LayoutSlug = props => {
* @param {*} props
* @returns
*/
const Layout404 = (props) => {
return <>
404 Not found.
</>
const Layout404 = props => {
return <>404 Not found.</>
}
/**
@@ -252,28 +272,31 @@ const Layout404 = (props) => {
* @param {*} props
* @returns
*/
const LayoutCategoryIndex = (props) => {
const LayoutCategoryIndex = props => {
const { categoryOptions } = props
return (
<>
<div id='category-list' className='duration-200 flex flex-wrap'>
{categoryOptions?.map(category => {
return (
<Link
key={category.name}
href={`/category/${category.name}`}
passHref
legacyBehavior>
<div
className={'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'}>
<i className='mr-4 fas fa-folder' />{category.name}({category.count})
</div>
</Link>
)
})}
</div>
</>
<>
<div id='category-list' className='duration-200 flex flex-wrap'>
{categoryOptions?.map(category => {
return (
<Link
key={category.name}
href={`/category/${category.name}`}
passHref
legacyBehavior>
<div
className={
'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'
}>
<i className='mr-4 fas fa-folder' />
{category.name}({category.count})
</div>
</Link>
)
})}
</div>
</>
)
}
@@ -282,37 +305,43 @@ const LayoutCategoryIndex = (props) => {
* @param {*} props
* @returns
*/
const LayoutTagIndex = (props) => {
const LayoutTagIndex = props => {
const { tagOptions } = props
return (
<>
<div>
<div id='tags-list' className='duration-200 flex flex-wrap'>
{tagOptions.map(tag => {
return (
<div key={tag.name} className='p-2'>
<Link key={tag} href={`/tag/${encodeURIComponent(tag.name)}`} passHref
className={`cursor-pointer inline-block rounded hover:bg-gray-500 hover:text-white duration-200 mr-2 py-1 px-2 text-xs whitespace-nowrap dark:hover:text-white text-gray-600 hover:shadow-xl dark:border-gray-400 notion-${tag.color}_background dark:bg-gray-800`}>
<div className='font-light dark:text-gray-400'><i className='mr-1 fas fa-tag' /> {tag.name + (tag.count ? `(${tag.count})` : '')} </div>
</Link>
</div>
)
})}
</div>
</div>
</>
<>
<div>
<div id='tags-list' className='duration-200 flex flex-wrap'>
{tagOptions.map(tag => {
return (
<div key={tag.name} className='p-2'>
<Link
key={tag}
href={`/tag/${encodeURIComponent(tag.name)}`}
passHref
className={`cursor-pointer inline-block rounded hover:bg-gray-500 hover:text-white duration-200 mr-2 py-1 px-2 text-xs whitespace-nowrap dark:hover:text-white text-gray-600 hover:shadow-xl dark:border-gray-400 notion-${tag.color}_background dark:bg-gray-800`}>
<div className='font-light dark:text-gray-400'>
<i className='mr-1 fas fa-tag' />{' '}
{tag.name + (tag.count ? `(${tag.count})` : '')}{' '}
</div>
</Link>
</div>
)
})}
</div>
</div>
</>
)
}
export {
CONFIG as THEME_CONFIG,
LayoutBase,
LayoutIndex,
LayoutSearch,
LayoutArchive,
LayoutSlug,
Layout404,
LayoutPostList,
LayoutArchive,
LayoutBase,
LayoutCategoryIndex,
LayoutTagIndex
LayoutIndex,
LayoutPostList,
LayoutSearch,
LayoutSlug,
LayoutTagIndex,
CONFIG as THEME_CONFIG
}

View File

@@ -1,26 +1,26 @@
import CONFIG from './config'
import { createContext, useContext, useEffect, useState } from 'react'
import Header from './components/Nav'
import { useGlobal } from '@/lib/global'
import Comment from '@/components/Comment'
import replaceSearchResult from '@/components/Mark'
import NotionPage from '@/components/NotionPage'
import ShareBar from '@/components/ShareBar'
import { siteConfig } from '@/lib/config'
import { useGlobal } from '@/lib/global'
import { isBrowser } from '@/lib/utils'
import { Transition } from '@headlessui/react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { createContext, useContext, useEffect, useState } from 'react'
import { ArticleFooter } from './components/ArticleFooter'
import { ArticleInfo } from './components/ArticleInfo'
import { ArticleLock } from './components/ArticleLock'
import BlogArchiveItem from './components/BlogArchiveItem'
import { BlogListPage } from './components/BlogListPage'
import { BlogListScroll } from './components/BlogListScroll'
import { isBrowser } from '@/lib/utils'
import SearchNavBar from './components/SearchNavBar'
import BlogArchiveItem from './components/BlogArchiveItem'
import { ArticleLock } from './components/ArticleLock'
import NotionPage from '@/components/NotionPage'
import { ArticleInfo } from './components/ArticleInfo'
import Comment from '@/components/Comment'
import { ArticleFooter } from './components/ArticleFooter'
import ShareBar from '@/components/ShareBar'
import Link from 'next/link'
import { Transition } from '@headlessui/react'
import BottomNav from './components/BottomNav'
import Modal from './components/Modal'
import Header from './components/Nav'
import SearchNavBar from './components/SearchNavBar'
import CONFIG from './config'
import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
import { useRouter } from 'next/router'
// 主题全局状态
const ThemeGlobalPlog = createContext()
@@ -52,42 +52,45 @@ const LayoutBase = props => {
}, [router.events])
return (
<ThemeGlobalPlog.Provider value={{ showModal, setShowModal, modalContent, setModalContent }}>
<div id='theme-plog' className={`${siteConfig('FONT_STYLE')} plog relative dark:text-gray-300 w-full dark:bg-black min-h-screen scroll-smooth`} >
<ThemeGlobalPlog.Provider
value={{ showModal, setShowModal, modalContent, setModalContent }}>
<div
id='theme-plog'
className={`${siteConfig('FONT_STYLE')} plog relative dark:text-gray-300 w-full dark:bg-black min-h-screen scroll-smooth`}>
<Style />
<Style/>
{/* 移动端顶部导航栏 */}
<Header {...props} />
{/* 移动端顶部导航栏 */}
<Header {...props} />
{/* 主区 */}
<main
id='out-wrapper'
className={
'relative m-auto flex-grow w-full transition-all pb-16 pt-16 md:pt-0'
}>
<Transition
show={!onLoading}
appear={true}
enter='transition ease-in-out duration-700 transform order-first'
enterFrom='opacity-0 translate-y-16'
enterTo='opacity-100'
leave='transition ease-in-out duration-300 transform'
leaveFrom='opacity-100 translate-y-0'
leaveTo='opacity-0 -translate-y-16'
unmount={false}>
{/* 顶部插槽 */}
{topSlot}
{children}
</Transition>
</main>
{/* 主区 */}
<main id='out-wrapper' className={'relative m-auto flex-grow w-full transition-all pb-16 pt-16 md:pt-0'}>
{/* 弹出框 - 用于放大显示首页图片等作用 */}
<Modal {...props} />
<Transition
show={!onLoading}
appear={true}
enter="transition ease-in-out duration-700 transform order-first"
enterFrom="opacity-0 translate-y-16"
enterTo="opacity-100"
leave="transition ease-in-out duration-300 transform"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 -translate-y-16"
unmount={false}
>
{/* 顶部插槽 */}
{topSlot}
{children}
</Transition>
</main>
{/* 弹出框 - 用于放大显示首页图片等作用 */}
<Modal {...props}/>
{/* 桌面端底部导航栏 */}
<BottomNav {...props} />
</div>
</ThemeGlobalPlog.Provider >
{/* 桌面端底部导航栏 */}
<BottomNav {...props} />
</div>
</ThemeGlobalPlog.Provider>
)
}
@@ -98,9 +101,7 @@ const LayoutBase = props => {
* @returns
*/
const LayoutIndex = props => {
return (
<LayoutPostList {...props} />
)
return <LayoutPostList {...props} />
}
/**
@@ -110,9 +111,13 @@ const LayoutIndex = props => {
*/
const LayoutPostList = props => {
return (
<>
{siteConfig('POST_LIST_STYLE') === 'page' ? <BlogListPage {...props} /> : <BlogListScroll {...props} />}
</>
<>
{siteConfig('POST_LIST_STYLE') === 'page' ? (
<BlogListPage {...props} />
) : (
<BlogListScroll {...props} />
)}
</>
)
}
@@ -149,11 +154,17 @@ const LayoutSearch = props => {
const LayoutArchive = props => {
const { archivePosts } = props
return (
<>
<div className="mb-10 pb-20 md:py-12 p-3 min-h-screen w-full">
{Object.keys(archivePosts).map(archiveTitle => <BlogArchiveItem key={archiveTitle} archiveTitle={archiveTitle} archivePosts={archivePosts} />)}
</div>
</>
<>
<div className='mb-10 pb-20 md:py-12 p-3 min-h-screen w-full'>
{Object.keys(archivePosts).map(archiveTitle => (
<BlogArchiveItem
key={archiveTitle}
archiveTitle={archiveTitle}
archivePosts={archivePosts}
/>
))}
</div>
</>
)
}
@@ -168,34 +179,39 @@ const LayoutSlug = props => {
useEffect(() => {
// 404
if (!post) {
setTimeout(() => {
if (isBrowser) {
const article = document.getElementById('notion-article')
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
setTimeout(
() => {
if (isBrowser) {
const article = document.getElementById('notion-article')
if (!article) {
router.push('/404').then(() => {
console.warn('找不到页面', router.asPath)
})
}
}
}
}, siteConfig('POST_WAITING_TIME_FOR_404') * 1000)
},
siteConfig('POST_WAITING_TIME_FOR_404') * 1000
)
}
}, [post])
return (
<>
<>
{lock && <ArticleLock validPassword={validPassword} />}
{lock && <ArticleLock validPassword={validPassword} />}
{!lock && <div id="article-wrapper" className="px-2 my-16 max-w-6xl mx-auto">
<>
<ArticleInfo post={post} />
<NotionPage post={post} />
<ShareBar post={post} />
<Comment frontMatter={post} />
<ArticleFooter />
</>
</div>}
</>
{!lock && (
<div className='px-2 my-16 max-w-6xl mx-auto'>
<>
<ArticleInfo post={post} />
<div id='article-wrapper'>
<NotionPage post={post} />
</div>
<ShareBar post={post} />
<Comment frontMatter={post} />
<ArticleFooter />
</>
</div>
)}
</>
)
}
@@ -204,10 +220,8 @@ const LayoutSlug = props => {
* @param {*} props
* @returns
*/
const Layout404 = (props) => {
return <>
404 Not found.
</>
const Layout404 = props => {
return <>404 Not found.</>
}
/**
@@ -215,28 +229,31 @@ const Layout404 = (props) => {
* @param {*} props
* @returns
*/
const LayoutCategoryIndex = (props) => {
const LayoutCategoryIndex = props => {
const { categoryOptions } = props
return (
<>
<div id='category-list' className='duration-200 flex flex-wrap'>
{categoryOptions?.map(category => {
return (
<Link
key={category.name}
href={`/category/${category.name}`}
passHref
legacyBehavior>
<div
className={'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'}>
<i className='mr-4 fas fa-folder' />{category.name}({category.count})
</div>
</Link>
)
})}
</div>
</>
<>
<div id='category-list' className='duration-200 flex flex-wrap'>
{categoryOptions?.map(category => {
return (
<Link
key={category.name}
href={`/category/${category.name}`}
passHref
legacyBehavior>
<div
className={
'hover:text-black dark:hover:text-white dark:text-gray-300 dark:hover:bg-gray-600 px-5 cursor-pointer py-2 hover:bg-gray-100'
}>
<i className='mr-4 fas fa-folder' />
{category.name}({category.count})
</div>
</Link>
)
})}
</div>
</>
)
}
@@ -245,37 +262,43 @@ const LayoutCategoryIndex = (props) => {
* @param {*} props
* @returns
*/
const LayoutTagIndex = (props) => {
const LayoutTagIndex = props => {
const { tagOptions } = props
return (
<>
<div>
<div id='tags-list' className='duration-200 flex flex-wrap'>
{tagOptions.map(tag => {
return (
<div key={tag.name} className='p-2'>
<Link key={tag} href={`/tag/${encodeURIComponent(tag.name)}`} passHref
className={`cursor-pointer inline-block rounded hover:bg-gray-500 hover:text-white duration-200 mr-2 py-1 px-2 text-xs whitespace-nowrap dark:hover:text-white text-gray-600 hover:shadow-xl dark:border-gray-400 notion-${tag.color}_background dark:bg-gray-800`}>
<div className='font-light dark:text-gray-400'><i className='mr-1 fas fa-tag' /> {tag.name + (tag.count ? `(${tag.count})` : '')} </div>
</Link>
</div>
)
})}
</div>
</div>
</>
<>
<div>
<div id='tags-list' className='duration-200 flex flex-wrap'>
{tagOptions.map(tag => {
return (
<div key={tag.name} className='p-2'>
<Link
key={tag}
href={`/tag/${encodeURIComponent(tag.name)}`}
passHref
className={`cursor-pointer inline-block rounded hover:bg-gray-500 hover:text-white duration-200 mr-2 py-1 px-2 text-xs whitespace-nowrap dark:hover:text-white text-gray-600 hover:shadow-xl dark:border-gray-400 notion-${tag.color}_background dark:bg-gray-800`}>
<div className='font-light dark:text-gray-400'>
<i className='mr-1 fas fa-tag' />{' '}
{tag.name + (tag.count ? `(${tag.count})` : '')}{' '}
</div>
</Link>
</div>
)
})}
</div>
</div>
</>
)
}
export {
CONFIG as THEME_CONFIG,
LayoutBase,
LayoutIndex,
LayoutSearch,
LayoutArchive,
LayoutSlug,
Layout404,
LayoutPostList,
LayoutArchive,
LayoutBase,
LayoutCategoryIndex,
LayoutTagIndex
LayoutIndex,
LayoutPostList,
LayoutSearch,
LayoutSlug,
LayoutTagIndex,
CONFIG as THEME_CONFIG
}

View File

@@ -224,9 +224,7 @@ const LayoutSlug = props => {
<>
{lock && <ArticleLock validPassword={validPassword} />}
<div
id='article-wrapper'
className={`px-2 ${fullWidth ? '' : 'xl:max-w-4xl 2xl:max-w-6xl'}`}>
<div className={`px-2 ${fullWidth ? '' : 'xl:max-w-4xl 2xl:max-w-6xl'}`}>
{/* 文章信息 */}
<ArticleInfo post={post} />
@@ -234,8 +232,10 @@ const LayoutSlug = props => {
{/* <AdSlot type={'in-article'} /> */}
<WWAds orientation='horizontal' className='w-full' />
{/* Notion文章主体 */}
{!lock && <NotionPage post={post} />}
<div id='article-wrapper'>
{/* Notion文章主体 */}
{!lock && <NotionPage post={post} />}
</div>
{/* 分享 */}
<ShareBar post={post} />

View File

@@ -143,8 +143,8 @@ const LayoutSlug = props => {
<Banner title={post?.title} description={post?.summary} />
<div className='container grow'>
<div className='flex flex-wrap justify-center -mx-4'>
<div className='w-full p-4'>
<div id='container-inner' className='mx-auto'>
<div id='container-inner' className='w-full p-4'>
<div id='article-wrapper' className='mx-auto'>
<NotionPage {...props} />
</div>
</div>

View File

@@ -99,7 +99,9 @@ const checkThemeDOM = () => {
elements[elements.length - 1].scrollIntoView()
// 删除前面的元素,只保留最后一个元素
for (let i = 0; i < elements.length - 1; i++) {
elements[i].parentNode.removeChild(elements[i])
if (elements[i] && elements[i].parentNode && elements[i].parentNode.contains(elements[i])) {
elements[i].parentNode.removeChild(elements[i])
}
}
}
}