mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-06-09 07:26:47 +00:00
feat(初步实现spoiler插件):
This commit is contained in:
@@ -298,6 +298,8 @@ const BLOG = {
|
|||||||
WIDGET_PET_SWITCH_THEME:
|
WIDGET_PET_SWITCH_THEME:
|
||||||
process.env.NEXT_PUBLIC_WIDGET_PET_SWITCH_THEME || true, // 点击宠物挂件切换博客主题
|
process.env.NEXT_PUBLIC_WIDGET_PET_SWITCH_THEME || true, // 点击宠物挂件切换博客主题
|
||||||
|
|
||||||
|
SPOILER_TEXT_TAG: process.env.NEXT_PUBLIC_SPOILER_TEXT_TAG || '', // 默认的隐藏标签
|
||||||
|
|
||||||
// 音乐播放插件
|
// 音乐播放插件
|
||||||
MUSIC_PLAYER: process.env.NEXT_PUBLIC_MUSIC_PLAYER || false, // 是否使用音乐播放插件
|
MUSIC_PLAYER: process.env.NEXT_PUBLIC_MUSIC_PLAYER || false, // 是否使用音乐播放插件
|
||||||
MUSIC_PLAYER_VISIBLE: process.env.NEXT_PUBLIC_MUSIC_PLAYER_VISIBLE || true, // 是否在左下角显示播放和切换,如果使用播放器,打开自动播放再隐藏,就会以类似背景音乐的方式播放,无法取消和暂停
|
MUSIC_PLAYER_VISIBLE: process.env.NEXT_PUBLIC_MUSIC_PLAYER_VISIBLE || true, // 是否在左下角显示播放和切换,如果使用播放器,打开自动播放再隐藏,就会以类似背景音乐的方式播放,无法取消和暂停
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
import { compressImage, mapImgUrl } from '@/lib/notion/mapImage'
|
import { compressImage, mapImgUrl } from '@/lib/notion/mapImage'
|
||||||
import { isBrowser } from '@/lib/utils'
|
import { isBrowser, loadExternalResource } from '@/lib/utils'
|
||||||
import mediumZoom from '@fisch0920/medium-zoom'
|
import mediumZoom from '@fisch0920/medium-zoom'
|
||||||
import 'katex/dist/katex.min.css'
|
import 'katex/dist/katex.min.css'
|
||||||
import dynamic from 'next/dynamic'
|
import dynamic from 'next/dynamic'
|
||||||
@@ -17,6 +17,7 @@ const NotionPage = ({ post, className }) => {
|
|||||||
// 是否关闭数据库和画册的点击跳转
|
// 是否关闭数据库和画册的点击跳转
|
||||||
const POST_DISABLE_GALLERY_CLICK = siteConfig('POST_DISABLE_GALLERY_CLICK')
|
const POST_DISABLE_GALLERY_CLICK = siteConfig('POST_DISABLE_GALLERY_CLICK')
|
||||||
const POST_DISABLE_DATABASE_CLICK = siteConfig('POST_DISABLE_DATABASE_CLICK')
|
const POST_DISABLE_DATABASE_CLICK = siteConfig('POST_DISABLE_DATABASE_CLICK')
|
||||||
|
const SPOILER_TEXT_TAG = siteConfig('SPOILER_TEXT_TAG')
|
||||||
|
|
||||||
const zoom =
|
const zoom =
|
||||||
isBrowser &&
|
isBrowser &&
|
||||||
@@ -84,6 +85,20 @@ const NotionPage = ({ post, className }) => {
|
|||||||
}
|
}
|
||||||
}, [post])
|
}, [post])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (SPOILER_TEXT_TAG) {
|
||||||
|
import('lodash/escapeRegExp').then(escapeRegExp => {
|
||||||
|
Promise.all([
|
||||||
|
loadExternalResource('/js/spoilerText.js', 'js'),
|
||||||
|
loadExternalResource('/css/spoiler-text.css', 'css')
|
||||||
|
]).then(() => {
|
||||||
|
window.textToSpoiler &&
|
||||||
|
window.textToSpoiler(escapeRegExp.default(SPOILER_TEXT_TAG))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [post])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id='notion-article'
|
id='notion-article'
|
||||||
|
|||||||
23
public/css/spoiler-text.css
Normal file
23
public/css/spoiler-text.css
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/* Spoiler text styles */
|
||||||
|
.spoiler-text {
|
||||||
|
color: transparent; /* 文字透明 */
|
||||||
|
background-color: #808080; /* 背景为黑色 */
|
||||||
|
border-color: #808080;
|
||||||
|
text-decoration-color: #808080;
|
||||||
|
text-emphasis-color: #808080;
|
||||||
|
border-radius: 8px;
|
||||||
|
filter: blur(1px); /* 初始模糊 */
|
||||||
|
--hide-transition: 0.3s ease-out;
|
||||||
|
transition: opacity var(--hide-transition),
|
||||||
|
filter var(--hide-transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
.spoiler-text:hover {
|
||||||
|
color: inherit; /* 鼠标悬停时恢复文字颜色 */
|
||||||
|
background-color: inherit; /* 鼠标悬停时恢复背景颜色 */
|
||||||
|
border-color: inherit;
|
||||||
|
text-decoration-color: inherit;
|
||||||
|
text-emphasis-color: inherit;
|
||||||
|
opacity: 1; /* 鼠标悬停时恢复不透明度 */
|
||||||
|
filter: blur(0); /* 鼠标悬停时解除模糊 */
|
||||||
|
}
|
||||||
66
public/js/spoilerText.js
Normal file
66
public/js/spoilerText.js
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
function convertTextToSpoilerSpan(node, className, spoilerTag) {
|
||||||
|
const regex = new RegExp(`${spoilerTag}(.*?)${spoilerTag}`, 'g')
|
||||||
|
const wholeText = node.wholeText
|
||||||
|
const fragments = []
|
||||||
|
let lastIndex = 0
|
||||||
|
let match
|
||||||
|
while ((match = regex.exec(wholeText)) !== null) {
|
||||||
|
console.log('符合要求的文字' + wholeText)
|
||||||
|
// 添加前面未匹配的部分
|
||||||
|
if (match.index > lastIndex) {
|
||||||
|
fragments.push(
|
||||||
|
document.createTextNode(wholeText.slice(lastIndex, match.index))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建 span 包裹的内容
|
||||||
|
const span = document.createElement('span')
|
||||||
|
span.textContent = match[1] // 提取匹配的内容
|
||||||
|
if (className) {
|
||||||
|
span.className = className
|
||||||
|
}
|
||||||
|
fragments.push(span)
|
||||||
|
// 设置lastIndex
|
||||||
|
lastIndex = regex.lastIndex
|
||||||
|
}
|
||||||
|
if (fragments.length) {
|
||||||
|
// 添加剩余未匹配的部分
|
||||||
|
if (lastIndex < wholeText.length) {
|
||||||
|
fragments.push(document.createTextNode(wholeText.slice(lastIndex)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 替换原节点
|
||||||
|
fragments.forEach(fragment => {
|
||||||
|
node.parentNode.appendChild(fragment)
|
||||||
|
})
|
||||||
|
node.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function processTextNodes(root, className, spoilerTag) {
|
||||||
|
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null)
|
||||||
|
const waitProcessNodes = []
|
||||||
|
while (walker.nextNode()) {
|
||||||
|
const node = walker.currentNode
|
||||||
|
waitProcessNodes.push(node)
|
||||||
|
}
|
||||||
|
for (const waitProcessNode of waitProcessNodes) {
|
||||||
|
convertTextToSpoilerSpan(waitProcessNode, className, spoilerTag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function textToSpoiler(spoilerTag) {
|
||||||
|
const intervalID = setInterval(() => {
|
||||||
|
const articleElement = document.querySelector(
|
||||||
|
'#article-wrapper #notion-article main'
|
||||||
|
)
|
||||||
|
if (articleElement) {
|
||||||
|
setTimeout(() => {
|
||||||
|
processTextNodes(articleElement, 'spoiler-text', spoilerTag)
|
||||||
|
clearInterval(intervalID)
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.textToSpoiler = textToSpoiler
|
||||||
Reference in New Issue
Block a user