精减 markjs ,精减 animate.css

This commit is contained in:
tangly1024.com
2023-07-20 17:33:41 +08:00
parent e278777e56
commit 309f7e8215
18 changed files with 654 additions and 155 deletions

31
components/Mark.js Normal file
View File

@@ -0,0 +1,31 @@
import { loadExternalResource } from '@/lib/utils'
/**
* 将搜索结果的关键词高亮
*/
export default async function replaceSearchResult({ doms, search, target }) {
if (!doms || !search || !target) {
return
}
try {
const url = await loadExternalResource('https://cdnjs.cloudflare.com/ajax/libs/mark.js/8.11.1/mark.min.js', 'js')
console.log('markjs 加载成功', url, window.Mark)
console.log('------', doms)
const Mark = window.Mark
if (doms instanceof HTMLCollection) {
for (const container of doms) {
const re = new RegExp(search, 'gim')
const instance = new Mark(container)
instance.markRegExp(re, target)
}
} else {
const re = new RegExp(search, 'gim')
const instance = new Mark(doms)
instance.markRegExp(re, target)
}
} catch (error) {
console.error('markjs 加载失败', error)
}
}

View File

@@ -5,9 +5,9 @@ import React, { useEffect, useRef } from 'react'
// import { Code } from 'react-notion-x/build/third-party/code'
import TweetEmbed from 'react-tweet-embed'
import BLOG from '@/blog.config'
import 'katex/dist/katex.min.css'
import { mapImgUrl } from '@/lib/notion/mapImage'
import BLOG from '@/blog.config'
import { isBrowser } from '@/lib/utils'
const Code = dynamic(() =>

View File

@@ -25,7 +25,6 @@
"@headlessui/react": "^1.7.15",
"@next/bundle-analyzer": "^12.1.1",
"@vercel/analytics": "^1.0.0",
"animate.css": "^4.1.1",
"animejs": "^3.2.1",
"aos": "^3.0.0-beta.6",
"axios": ">=0.21.1",
@@ -35,7 +34,6 @@
"js-md5": "^0.7.3",
"localStorage": "^1.0.4",
"lodash.throttle": "^4.1.1",
"mark.js": "^8.11.1",
"memory-cache": "^0.2.0",
"mongodb": "^4.6.0",
"next": "13.3.1",

View File

@@ -1,6 +1,6 @@
import { useEffect } from 'react'
import 'animate.css'
import '@/styles/animate.css' // @see https://animate.style/
import '@/styles/globals.css'
import '@/styles/nprogress.css'
import '@/styles/utility-patterns.css'

503
styles/animate.css vendored Normal file
View File

@@ -0,0 +1,503 @@
@charset "UTF-8";/*!
* animate.css - https://animate.style/
* Version - 4.1.1
* Licensed under the MIT license - http://opensource.org/licenses/MIT
* https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css
* 这里做了精减后续不再使用animate.css因为占用体积太大不如手写动画
* Copyright (c) 2020 Animate.css
*/
:root {
--animate-duration: 1s;
--animate-delay: 1s;
--animate-repeat: 1;
}
.animate__animated {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-duration: var(--animate-duration);
animation-duration: var(--animate-duration);
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.animate__animated.animate__faster {
-webkit-animation-duration: calc(1s / 2);
animation-duration: calc(1s / 2);
-webkit-animation-duration: calc(var(--animate-duration) / 2);
animation-duration: calc(var(--animate-duration) / 2);
}
.animate__animated.animate__fast {
-webkit-animation-duration: calc(1s * 0.8);
animation-duration: calc(1s * 0.8);
-webkit-animation-duration: calc(var(--animate-duration) * 0.8);
animation-duration: calc(var(--animate-duration) * 0.8);
}
@media print, (prefers-reduced-motion: reduce) {
.animate__animated {
-webkit-animation-duration: 1ms !important;
animation-duration: 1ms !important;
-webkit-transition-duration: 1ms !important;
transition-duration: 1ms !important;
-webkit-animation-iteration-count: 1 !important;
animation-iteration-count: 1 !important;
}
.animate__animated[class*='Out'] {
opacity: 0;
}
}
@-webkit-keyframes shakeX {
from,
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
10%,
30%,
50%,
70%,
90% {
-webkit-transform: translate3d(-10px, 0, 0);
transform: translate3d(-10px, 0, 0);
}
20%,
40%,
60%,
80% {
-webkit-transform: translate3d(10px, 0, 0);
transform: translate3d(10px, 0, 0);
}
}
@keyframes shakeX {
from,
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
10%,
30%,
50%,
70%,
90% {
-webkit-transform: translate3d(-10px, 0, 0);
transform: translate3d(-10px, 0, 0);
}
20%,
40%,
60%,
80% {
-webkit-transform: translate3d(10px, 0, 0);
transform: translate3d(10px, 0, 0);
}
}
.animate__shakeX {
-webkit-animation-name: shakeX;
animation-name: shakeX;
}
@-webkit-keyframes shakeY {
from,
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
10%,
30%,
50%,
70%,
90% {
-webkit-transform: translate3d(0, -10px, 0);
transform: translate3d(0, -10px, 0);
}
20%,
40%,
60%,
80% {
-webkit-transform: translate3d(0, 10px, 0);
transform: translate3d(0, 10px, 0);
}
}
@keyframes shakeY {
from,
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
10%,
30%,
50%,
70%,
90% {
-webkit-transform: translate3d(0, -10px, 0);
transform: translate3d(0, -10px, 0);
}
20%,
40%,
60%,
80% {
-webkit-transform: translate3d(0, 10px, 0);
transform: translate3d(0, 10px, 0);
}
}
.animate__shakeY {
-webkit-animation-name: shakeY;
animation-name: shakeY;
}
@-webkit-keyframes headShake {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
6.5% {
-webkit-transform: translateX(-6px) rotateY(-9deg);
transform: translateX(-6px) rotateY(-9deg);
}
18.5% {
-webkit-transform: translateX(5px) rotateY(7deg);
transform: translateX(5px) rotateY(7deg);
}
31.5% {
-webkit-transform: translateX(-3px) rotateY(-5deg);
transform: translateX(-3px) rotateY(-5deg);
}
43.5% {
-webkit-transform: translateX(2px) rotateY(3deg);
transform: translateX(2px) rotateY(3deg);
}
50% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
@keyframes headShake {
0% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
6.5% {
-webkit-transform: translateX(-6px) rotateY(-9deg);
transform: translateX(-6px) rotateY(-9deg);
}
18.5% {
-webkit-transform: translateX(5px) rotateY(7deg);
transform: translateX(5px) rotateY(7deg);
}
31.5% {
-webkit-transform: translateX(-3px) rotateY(-5deg);
transform: translateX(-3px) rotateY(-5deg);
}
43.5% {
-webkit-transform: translateX(2px) rotateY(3deg);
transform: translateX(2px) rotateY(3deg);
}
50% {
-webkit-transform: translateX(0);
transform: translateX(0);
}
}
.animate__headShake {
-webkit-animation-timing-function: ease-in-out;
animation-timing-function: ease-in-out;
-webkit-animation-name: headShake;
animation-name: headShake;
}
@keyframes jello {
from,
11.1%,
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
22.2% {
-webkit-transform: skewX(-12.5deg) skewY(-12.5deg);
transform: skewX(-12.5deg) skewY(-12.5deg);
}
33.3% {
-webkit-transform: skewX(6.25deg) skewY(6.25deg);
transform: skewX(6.25deg) skewY(6.25deg);
}
44.4% {
-webkit-transform: skewX(-3.125deg) skewY(-3.125deg);
transform: skewX(-3.125deg) skewY(-3.125deg);
}
55.5% {
-webkit-transform: skewX(1.5625deg) skewY(1.5625deg);
transform: skewX(1.5625deg) skewY(1.5625deg);
}
66.6% {
-webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg);
transform: skewX(-0.78125deg) skewY(-0.78125deg);
}
77.7% {
-webkit-transform: skewX(0.390625deg) skewY(0.390625deg);
transform: skewX(0.390625deg) skewY(0.390625deg);
}
88.8% {
-webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
transform: skewX(-0.1953125deg) skewY(-0.1953125deg);
}
}
.animate__jello {
-webkit-animation-name: jello;
animation-name: jello;
-webkit-transform-origin: center;
transform-origin: center;
}
@-webkit-keyframes bounceInRight {
from,
60%,
75%,
90%,
to {
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
from {
opacity: 0;
-webkit-transform: translate3d(3000px, 0, 0) scaleX(3);
transform: translate3d(3000px, 0, 0) scaleX(3);
}
60% {
opacity: 1;
-webkit-transform: translate3d(-25px, 0, 0) scaleX(1);
transform: translate3d(-25px, 0, 0) scaleX(1);
}
75% {
-webkit-transform: translate3d(10px, 0, 0) scaleX(0.98);
transform: translate3d(10px, 0, 0) scaleX(0.98);
}
90% {
-webkit-transform: translate3d(-5px, 0, 0) scaleX(0.995);
transform: translate3d(-5px, 0, 0) scaleX(0.995);
}
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
@keyframes bounceInRight {
from,
60%,
75%,
90%,
to {
-webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
from {
opacity: 0;
-webkit-transform: translate3d(3000px, 0, 0) scaleX(3);
transform: translate3d(3000px, 0, 0) scaleX(3);
}
60% {
opacity: 1;
-webkit-transform: translate3d(-25px, 0, 0) scaleX(1);
transform: translate3d(-25px, 0, 0) scaleX(1);
}
75% {
-webkit-transform: translate3d(10px, 0, 0) scaleX(0.98);
transform: translate3d(10px, 0, 0) scaleX(0.98);
}
90% {
-webkit-transform: translate3d(-5px, 0, 0) scaleX(0.995);
transform: translate3d(-5px, 0, 0) scaleX(0.995);
}
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
.animate__bounceInRight {
-webkit-animation-name: bounceInRight;
animation-name: bounceInRight;
}
/* Fading entrances */
@-webkit-keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.animate__fadeIn {
-webkit-animation-name: fadeIn;
animation-name: fadeIn;
}
/* Fading exits */
/* 删除 */
/* Flippers */
/* 删除 */
/* Lightspeed */
/* 删除 */
/* Rotating exits */
/* 删除 */
/* Zooming entrances */
/* 删除 */
/* Sliding entrances */
@-webkit-keyframes slideInLeft {
from {
-webkit-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
visibility: visible;
}
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
@keyframes slideInLeft {
from {
-webkit-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
visibility: visible;
}
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
.animate__slideInLeft {
-webkit-animation-name: slideInLeft;
animation-name: slideInLeft;
}
@-webkit-keyframes slideInRight {
from {
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
visibility: visible;
}
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
@keyframes slideInRight {
from {
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
visibility: visible;
}
to {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
}
.animate__slideInRight {
-webkit-animation-name: slideInRight;
animation-name: slideInRight;
}
@keyframes slideOutLeft {
from {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
to {
visibility: hidden;
-webkit-transform: translate3d(-100%, 0, 0);
transform: translate3d(-100%, 0, 0);
}
}
.animate__slideOutLeft {
-webkit-animation-name: slideOutLeft;
animation-name: slideOutLeft;
}
@-webkit-keyframes slideOutRight {
from {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
to {
visibility: hidden;
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
}
@keyframes slideOutRight {
from {
-webkit-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
to {
visibility: hidden;
-webkit-transform: translate3d(100%, 0, 0);
transform: translate3d(100%, 0, 0);
}
}
.animate__slideOutRight {
-webkit-animation-name: slideOutRight;
animation-name: slideOutRight;
}

View File

@@ -19,7 +19,7 @@ import NotionPage from '@/components/NotionPage'
import Comment from '@/components/Comment'
import ShareBar from '@/components/ShareBar'
import SearchInput from './components/SearchInput'
import Mark from 'mark.js'
import replaceSearchResult from '@/components/Mark'
import { isBrowser } from '@/lib/utils'
import BlogListGroupByDate from './components/BlogListGroupByDate'
import CategoryItem from './components/CategoryItem'
@@ -175,21 +175,20 @@ const LayoutSearch = props => {
const slotTop = <div className='pb-12'><SearchInput {...props} /></div>
const router = useRouter()
useEffect(() => {
setTimeout(() => {
if (isBrowser()) {
// 高亮搜索到的结果
const container = document.getElementById('posts-wrapper')
console.log('container', container, keyword)
if (keyword && container) {
const re = new RegExp(keyword, 'gim')
const instance = new Mark(container)
instance.markRegExp(re, {
if (isBrowser()) {
// 高亮搜索到的结果
const container = document.getElementById('posts-wrapper')
if (keyword && container) {
replaceSearchResult({
doms: container,
search: keyword,
target: {
element: 'span',
className: 'text-red-500 border-b border-dashed'
})
}
}
})
}
}, 500)
}
}, [router])
return <LayoutPostList slotTop={slotTop} {...props} />

View File

@@ -20,9 +20,9 @@ import { Transition } from '@headlessui/react'
import dynamic from 'next/dynamic'
import { AdSlot } from '@/components/GoogleAdsense'
import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
const Live2D = dynamic(() => import('@/components/Live2D'))
const Mark = dynamic(() => import('mark.js'))
// 主题全局状态
const ThemeGlobalFukasawa = createContext()
@@ -148,17 +148,16 @@ const LayoutSearch = props => {
const { keyword } = props
const router = useRouter()
useEffect(() => {
setTimeout(() => {
const container = isBrowser() && document.getElementById('posts-wrapper')
if (container && container.innerHTML) {
const re = new RegExp(keyword, 'gim')
const instance = new Mark(container)
instance.markRegExp(re, {
if (isBrowser()) {
replaceSearchResult({
doms: document.getElementById('posts-wrapper'),
search: keyword,
target: {
element: 'span',
className: 'text-red-500 border-b border-dashed'
})
}
}, 300)
}
})
}
}, [router])
return <LayoutPostList {...props} />
}

View File

@@ -54,8 +54,8 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => {
{/* 搜索结果 */}
{post.results && (
<p className="line-clamp-2 mt-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
{post.results.map(r => (
<span key={r}>{r}</span>
{post.results.map((r, index) => (
<span key={index}>{r}</span>
))}
</p>
)}

View File

@@ -7,12 +7,10 @@ import SideRight from './components/SideRight'
import NavBar from './components/NavBar'
import { useGlobal } from '@/lib/global'
import BLOG from '@/blog.config'
import { isBrowser, loadExternalResource } from '@/lib/utils'
import BlogPostListPage from './components/BlogPostListPage'
import BlogPostListScroll from './components/BlogPostListScroll'
import Hero from './components/Hero'
import { useRouter } from 'next/router'
import Mark from 'mark.js'
import SearchNav from './components/SearchNav'
import BlogPostArchive from './components/BlogPostArchive'
import { ArticleLock } from './components/ArticleLock'
@@ -31,6 +29,7 @@ import { NoticeBar } from './components/NoticeBar'
import { HashTag } from '@/components/HeroIcons'
import LatestPostsGroup from './components/LatestPostsGroup'
import FloatTocButton from './components/FloatTocButton'
import replaceSearchResult from '@/components/Mark'
/**
* 基础布局 采用上中下布局,移动端使用顶部侧边导航栏
@@ -42,11 +41,6 @@ const LayoutBase = props => {
const { children, headerSlot, slotTop, slotRight, meta, siteInfo, className } = props
const { onLoading } = useGlobal()
// 加载主题样式
if (isBrowser()) {
loadExternalResource('/css/theme-hexo.css', 'css')
}
return (
<div id='theme-heo' className='bg-[#f7f9fe] dark:bg-[#18171d] h-full min-h-screen flex flex-col'>
{/* 网页SEO */}
@@ -168,23 +162,20 @@ const LayoutSearch = props => {
</header>
useEffect(() => {
setTimeout(() => {
if (currentSearch) {
const targets = document.getElementsByClassName('replace')
for (const container of targets) {
if (container && container.innerHTML) {
const re = new RegExp(currentSearch, 'gim')
const instance = new Mark(container)
instance.markRegExp(re, {
element: 'span',
className: 'text-red-500 border-b border-dashed'
})
// 高亮搜索结果
if (currentSearch) {
setTimeout(() => {
replaceSearchResult({
doms: document.getElementsByClassName('replace'),
search: currentSearch,
target: {
element: 'span',
className: 'text-red-500 border-b border-dashed'
}
}
}
}, 100)
})
})
}, 100)
}
}, [])
return (
<LayoutBase {...props} currentSearch={currentSearch} headerSlot={headerSlot}>
<div id='post-outer-wrapper' className='px-5 lg:px-0'>

View File

@@ -51,9 +51,9 @@ export const BlogPostCardInfo = ({ post, showPreview, showPageCover, showSummary
{/* 搜索结果 */}
{post.results && (
<p className="line-clamp-2 mt-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
{post.results.map(r => (
<span key={r}>{r}</span>
))}
{post.results.map((r, index) => (
<span key={index}>{r}</span>
))}
</p>
)}
{/* 预览 */}

View File

@@ -12,7 +12,6 @@ import BlogPostListPage from './components/BlogPostListPage'
import BlogPostListScroll from './components/BlogPostListScroll'
import Hero from './components/Hero'
import { useRouter } from 'next/router'
import Mark from 'mark.js'
import Card from './components/Card'
import RightFloatArea from './components/RightFloatArea'
import SearchNav from './components/SearchNav'
@@ -33,6 +32,7 @@ import Link from 'next/link'
import SlotBar from './components/SlotBar'
import { Transition } from '@headlessui/react'
import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
/**
* 基础布局 采用左右两侧布局,移动端使用顶部导航栏
@@ -139,21 +139,16 @@ const LayoutSearch = props => {
const currentSearch = keyword || router?.query?.s
useEffect(() => {
setTimeout(() => {
if (currentSearch) {
const targets = document.getElementsByClassName('replace')
for (const container of targets) {
if (container && container.innerHTML) {
const re = new RegExp(currentSearch, 'gim')
const instance = new Mark(container)
instance.markRegExp(re, {
element: 'span',
className: 'text-red-500 border-b border-dashed'
})
}
if (currentSearch) {
replaceSearchResult({
doms: document.getElementsByClassName('replace'),
search: keyword,
target: {
element: 'span',
className: 'text-red-500 border-b border-dashed'
}
}
}, 100)
})
}
})
return (

View File

@@ -8,7 +8,6 @@ import Footer from './components/Footer'
import { useEffect } from 'react'
import RightFloatButtons from './components/RightFloatButtons'
import { useRouter } from 'next/router'
import Mark from 'mark.js'
import SearchNave from './components/SearchNav'
import BlogPostListPage from './components/BlogPostListPage'
import BlogPostListScroll from './components/BlogPostListScroll'
@@ -31,6 +30,7 @@ import JumpToCommentButton from './components/JumpToCommentButton'
import BlogListBar from './components/BlogListBar'
import { Transition } from '@headlessui/react'
import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
/**
* 基础布局
@@ -140,21 +140,16 @@ const LayoutSearch = props => {
const currentSearch = keyword || router?.query?.s
useEffect(() => {
setTimeout(() => {
if (currentSearch) {
const targets = document.getElementsByClassName('replace')
for (const container of targets) {
if (container && container.innerHTML) {
const re = new RegExp(currentSearch, 'gim')
const instance = new Mark(container)
instance.markRegExp(re, {
element: 'span',
className: 'text-red-500 border-b border-dashed'
})
}
if (currentSearch) {
replaceSearchResult({
doms: document.getElementsByClassName('replace'),
search: keyword,
target: {
element: 'span',
className: 'text-red-500 border-b border-dashed'
}
}
}, 100)
})
}
})
return (
<LayoutBase {...props} currentSearch={currentSearch}>

View File

@@ -22,7 +22,6 @@ import { ArticleLock } from './components/ArticleLock'
import TagGroups from './components/TagGroups'
import CategoryGroup from './components/CategoryGroup'
import { isBrowser } from '@/lib/utils'
import Mark from 'mark.js'
import BlogArchiveItem from './components/BlogArchiveItem'
import BlogPostBar from './components/BlogPostBar'
import NotionPage from '@/components/NotionPage'
@@ -35,6 +34,7 @@ import ShareBar from '@/components/ShareBar'
import Link from 'next/link'
import { Transition } from '@headlessui/react'
import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
// 主题全局状态
const ThemeGlobalMedium = createContext()
@@ -202,18 +202,18 @@ const LayoutSearch = (props) => {
const currentSearch = keyword || router?.query?.s
useEffect(() => {
setTimeout(() => {
const container = isBrowser() && document.getElementById('posts-wrapper')
if (container && container.innerHTML) {
const re = new RegExp(currentSearch, 'gim')
const instance = new Mark(container)
instance.markRegExp(re, {
if (isBrowser()) {
replaceSearchResult({
doms: document.getElementById('posts-wrapper'),
search: keyword,
target: {
element: 'span',
className: 'text-red-500 border-b border-dashed'
})
}
}, 100)
})
}
})
}
}, [])
return <LayoutBase {...props}>
{/* 搜索导航栏 */}

View File

@@ -86,8 +86,8 @@ const BlogPostCard = ({ post, showSummary }) => {
{/* 搜索结果 */}
{post.results && (
<p className="line-clamp-4 mt-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7">
{post.results.map(r => (
<span key={r}>{r}</span>
{post.results.map((r, index) => (
<span key={index}>{r}</span>
))}
</p>
)}

View File

@@ -16,7 +16,6 @@ import BlogPostListScroll from './components/BlogPostListScroll'
import BlogPostListPage from './components/BlogPostListPage'
import StickyBar from './components/StickyBar'
import { isBrowser } from '@/lib/utils'
import Mark from 'mark.js'
import TocDrawerButton from './components/TocDrawerButton'
import TocDrawer from './components/TocDrawer'
import { ArticleLock } from './components/ArticleLock'
@@ -28,6 +27,7 @@ import Link from 'next/link'
import BlogListBar from './components/BlogListBar'
import { Transition } from '@headlessui/react'
import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
/**
* 基础布局 采用左中右三栏布局,移动端使用顶部导航栏
@@ -161,17 +161,20 @@ const LayoutPostList = (props) => {
const LayoutSearch = (props) => {
const { locale } = useGlobal()
const { posts, keyword } = props
setTimeout(() => {
const container = isBrowser() && document.getElementById('posts-wrapper')
if (container && container.innerHTML) {
const re = new RegExp(keyword, 'gim')
const instance = new Mark(container)
instance.markRegExp(re, {
element: 'span',
className: 'text-red-500 border-b border-dashed'
useEffect(() => {
if (isBrowser()) {
replaceSearchResult({
doms: document.getElementById('posts-wrapper'),
search: keyword,
target: {
element: 'span',
className: 'text-red-500 border-b border-dashed'
}
})
}
}, 200)
}, [])
return (
<LayoutBase {...props} >
<StickyBar>

View File

@@ -1,3 +1,4 @@
import BLOG from '@/blog.config'
import CONFIG from './config'
import CommonHead from '@/components/CommonHead'
import React, { useEffect, useState } from 'react'
@@ -6,15 +7,9 @@ import { Footer } from './components/Footer'
import JumpToTopButton from './components/JumpToTopButton'
import Live2D from '@/components/Live2D'
import { useGlobal } from '@/lib/global'
import BLOG from '@/blog.config'
import Announcement from './components/Announcement'
import { BlogListPage } from './components/BlogListPage'
import { BlogListScroll } from './components/BlogListScroll'
import { useRouter } from 'next/router'
import Mark from 'mark.js'
import { deepClone, isBrowser } from '@/lib/utils'
import SearchNavBar from './components/SearchNavBar'
import BlogArchiveItem from './components/BlogArchiveItem'
@@ -28,6 +23,7 @@ import Link from 'next/link'
import BlogListBar from './components/BlogListBar'
import { Transition } from '@headlessui/react'
import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
/**
* 基础布局 采用左右两侧布局,移动端使用顶部导航栏
@@ -135,22 +131,18 @@ const LayoutPostList = props => {
*/
const LayoutSearch = props => {
const { keyword } = props
const router = useRouter()
useEffect(() => {
setTimeout(() => {
const container = isBrowser() && document.getElementById('posts-wrapper')
if (container && container.innerHTML) {
const re = new RegExp(keyword, 'gim')
const instance = new Mark(container)
instance.markRegExp(re, {
if (isBrowser()) {
replaceSearchResult({
doms: document.getElementById('posts-wrapper'),
search: keyword,
target: {
element: 'span',
className: 'text-red-500 border-b border-dashed'
})
}
}, 100)
}, [router.events])
}
})
}
}, [])
return <LayoutPostList {...props} slotTop={<SearchNavBar {...props} />} />
}

View File

@@ -7,10 +7,6 @@ import { useGlobal } from '@/lib/global'
import BLOG from '@/blog.config'
import { BlogListPage } from './components/BlogListPage'
import { BlogListScroll } from './components/BlogListScroll'
import { useRouter } from 'next/router'
import Mark from 'mark.js'
import { isBrowser } from '@/lib/utils'
import SearchNavBar from './components/SearchNavBar'
import BlogArchiveItem from './components/BlogArchiveItem'
@@ -26,6 +22,7 @@ import BottomNav from './components/BottomNav'
import { saveDarkModeToCookies } from '@/themes/theme'
import Modal from './components/Modal'
import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
// 主题全局状态
const ThemeGlobalPlog = createContext()
@@ -133,21 +130,19 @@ const LayoutPostList = props => {
*/
const LayoutSearch = props => {
const { keyword } = props
const router = useRouter()
useEffect(() => {
setTimeout(() => {
const container = isBrowser() && document.getElementById('posts-wrapper')
if (container && container.innerHTML) {
const re = new RegExp(keyword, 'gim')
const instance = new Mark(container)
instance.markRegExp(re, {
if (isBrowser()) {
replaceSearchResult({
doms: document.getElementById('posts-wrapper'),
search: keyword,
target: {
element: 'span',
className: 'text-red-500 border-b border-dashed'
})
}
}, 100)
}, [router.events])
}
})
}
}, [])
return <LayoutPostList {...props} topSlot={<SearchNavBar {...props} />} />
}

View File

@@ -1,9 +1,7 @@
import CONFIG from './config'
import { BlogListPage } from './components/BlogListPage'
import { BlogListScroll } from './components/BlogListScroll'
import { useRouter } from 'next/router'
import { useEffect } from 'react'
import Mark from 'mark.js'
import { isBrowser, loadExternalResource } from '@/lib/utils'
import BlogArchiveItem from './components/BlogArchiveItem'
import { ArticleLock } from './components/ArticleLock'
@@ -26,6 +24,7 @@ import { useGlobal } from '@/lib/global'
import SearchInput from './components/SearchInput'
import { Transition } from '@headlessui/react'
import { Style } from './style'
import replaceSearchResult from '@/components/Mark'
/**
* 基础布局
@@ -120,20 +119,19 @@ const LayoutPostList = props => {
*/
const LayoutSearch = props => {
const { keyword } = props
const router = useRouter()
useEffect(() => {
setTimeout(() => {
const container = isBrowser() && document.getElementById('posts-wrapper')
if (container && container.innerHTML) {
const re = new RegExp(keyword, 'gim')
const instance = new Mark(container)
instance.markRegExp(re, {
if (isBrowser()) {
replaceSearchResult({
doms: document.getElementById('posts-wrapper'),
search: keyword,
target: {
element: 'span',
className: 'text-red-500 border-b border-dashed'
})
}
}, 100)
}, [router])
}
})
}
}, [])
return <LayoutPostList {...props} slotTop={<SearchInput {...props} />} />
}