diff --git a/pages/search/[keyword].js b/pages/search/[keyword]/index.js
similarity index 93%
rename from pages/search/[keyword].js
rename to pages/search/[keyword]/index.js
index e478920d..91b55de6 100644
--- a/pages/search/[keyword].js
+++ b/pages/search/[keyword]/index.js
@@ -38,6 +38,13 @@ export async function getStaticProps({ params: { keyword } }) {
const { allPages } = props
const allPosts = allPages.filter(page => page.type === 'Post' && page.status === 'Published')
props.posts = await filterByMemCache(allPosts, keyword)
+ props.postCount = props.posts.length
+ // 处理分页
+ if (BLOG.POST_LIST_STYLE === 'scroll') {
+ // 滚动列表 给前端返回所有数据
+ } else if (BLOG.POST_LIST_STYLE === 'page') {
+ props.posts = props.posts?.slice(0, BLOG.POSTS_PER_PAGE - 1)
+ }
props.keyword = keyword
return {
props,
diff --git a/pages/search/[keyword]/page/[page].js b/pages/search/[keyword]/page/[page].js
new file mode 100644
index 00000000..6d4cf070
--- /dev/null
+++ b/pages/search/[keyword]/page/[page].js
@@ -0,0 +1,156 @@
+import { getGlobalNotionData } from '@/lib/notion/getNotionData'
+import { useGlobal } from '@/lib/global'
+import { getDataFromCache } from '@/lib/cache/cache_manager'
+import * as ThemeMap from '@/themes'
+import BLOG from '@/blog.config'
+
+const Index = props => {
+ const { keyword, siteInfo } = props
+ const { locale } = useGlobal()
+ const meta = {
+ title: `${keyword || ''}${keyword ? ' | ' : ''}${locale.NAV.SEARCH} | ${siteInfo?.title}`,
+ description: siteInfo?.title,
+ image: siteInfo?.pageCover,
+ slug: 'search/' + (keyword || ''),
+ type: 'website'
+ }
+ const { theme } = useGlobal()
+ const ThemeComponents = ThemeMap[theme]
+ return (
+
+ )
+}
+
+/**
+ * 服务端搜索
+ * @param {*} param0
+ * @returns
+ */
+export async function getStaticProps({ params: { keyword, page } }) {
+ const props = await getGlobalNotionData({
+ from: 'search-props',
+ pageType: ['Post']
+ })
+ const { allPages } = props
+ const allPosts = allPages.filter(page => page.type === 'Post' && page.status === 'Published')
+ props.posts = await filterByMemCache(allPosts, keyword)
+ props.postCount = props.posts.length
+ // 处理分页
+ props.posts = props.posts.slice(BLOG.POSTS_PER_PAGE * (page - 1), BLOG.POSTS_PER_PAGE * page - 1)
+ props.keyword = keyword
+ props.page = page
+ return {
+ props,
+ revalidate: 1
+ }
+}
+
+export async function getStaticPaths() {
+ return {
+ paths: [{ params: { keyword: BLOG.TITLE, page: '1' } }],
+ fallback: true
+ }
+}
+
+/**
+ * 将对象的指定字段拼接到字符串
+ * @param sourceTextArray
+ * @param targetObj
+ * @param key
+ * @returns {*}
+ */
+function appendText(sourceTextArray, targetObj, key) {
+ if (!targetObj) {
+ return sourceTextArray
+ }
+ const textArray = targetObj[key]
+ const text = textArray ? getTextContent(textArray) : ''
+ if (text && text !== 'Untitled') {
+ return sourceTextArray.concat(text)
+ }
+ return sourceTextArray
+}
+
+/**
+ * 递归获取层层嵌套的数组
+ * @param {*} textArray
+ * @returns
+ */
+function getTextContent(textArray) {
+ if (typeof textArray === 'object' && isIterable(textArray)) {
+ let result = ''
+ for (const textObj of textArray) {
+ result = result + getTextContent(textObj)
+ }
+ return result
+ } else if (typeof textArray === 'string') {
+ return textArray
+ }
+}
+
+/**
+ * 对象是否可以遍历
+ * @param {*} obj
+ * @returns
+ */
+const isIterable = obj =>
+ obj != null && typeof obj[Symbol.iterator] === 'function'
+
+/**
+ * 在内存缓存中进行全文索引
+ * @param {*} allPosts
+ * @param keyword 关键词
+ * @returns
+ */
+async function filterByMemCache(allPosts, keyword) {
+ const filterPosts = []
+ if (keyword) {
+ keyword = keyword.trim()
+ }
+ for (const post of allPosts) {
+ const cacheKey = 'page_block_' + post.id
+ const page = await getDataFromCache(cacheKey, true)
+ const tagContent = post.tags && Array.isArray(post.tags) ? post.tags.join(' ') : ''
+ const categoryContent = post.category && Array.isArray(post.category) ? post.category.join(' ') : ''
+ const articleInfo = post.title + post.summary + tagContent + categoryContent
+ let hit = articleInfo.indexOf(keyword) > -1
+ let indexContent = [post.summary]
+ if (page && page.block) {
+ const contentIds = Object.keys(page.block)
+ contentIds.forEach(id => {
+ const properties = page?.block[id]?.value?.properties
+ indexContent = appendText(indexContent, properties, 'title')
+ indexContent = appendText(indexContent, properties, 'caption')
+ })
+ }
+ // console.log('全文搜索缓存', cacheKey, page != null)
+ post.results = []
+ let hitCount = 0
+ for (const i in indexContent) {
+ const c = indexContent[i]
+ if (!c) {
+ continue
+ }
+ const index = c.toLowerCase().indexOf(keyword.toLowerCase())
+ if (index > -1) {
+ hit = true
+ hitCount += 1
+ post.results.push(c)
+ } else {
+ if ((post.results.length - 1) / hitCount < 3 || i === 0) {
+ post.results.push(c)
+ }
+ }
+ }
+ if (hit) {
+ filterPosts.push(post)
+ }
+ }
+ return filterPosts
+}
+
+export default Index
diff --git a/themes/example/LayoutIndex.js b/themes/example/LayoutIndex.js
index 17b77b4a..94eaac2f 100644
--- a/themes/example/LayoutIndex.js
+++ b/themes/example/LayoutIndex.js
@@ -1,11 +1,13 @@
+import BLOG from '@/blog.config'
import { BlogListPage } from './components/BlogListPage'
+import { BlogListScroll } from './components/BlogListScroll'
import LayoutBase from './LayoutBase'
export const LayoutIndex = props => {
return (
-
+ {BLOG.POST_LIST_STYLE === 'page' ? : }
)
}
diff --git a/themes/example/LayoutSearch.js b/themes/example/LayoutSearch.js
index 7c5dbafb..984e47e7 100644
--- a/themes/example/LayoutSearch.js
+++ b/themes/example/LayoutSearch.js
@@ -1,14 +1,14 @@
import BLOG from '@/blog.config'
-import { useGlobal } from '@/lib/global'
-import Link from 'next/link'
+import { BlogListPage } from './components/BlogListPage'
+import { BlogListScroll } from './components/BlogListScroll'
import { useRouter } from 'next/router'
-import { useEffect, useState } from 'react'
+import { useEffect } from 'react'
import SearchInput from './components/SearchInput'
import LayoutBase from './LayoutBase'
import { isBrowser } from '@/lib/utils'
export const LayoutSearch = props => {
- const { keyword, posts } = props
+ const { keyword } = props
const router = useRouter()
useEffect(() => {
@@ -21,22 +21,6 @@ export const LayoutSearch = props => {
}, 100)
}, [router.events])
- const { locale } = useGlobal()
-
- const [page, updatePage] = useState(1)
- let hasMore = false
- const postsToShow = posts
- ? Object.assign(posts).slice(0, BLOG.POSTS_PER_PAGE * page)
- : []
-
- if (posts) {
- const totalCount = posts.length
- hasMore = page * BLOG.POSTS_PER_PAGE < totalCount
- }
- const handleGetMore = () => {
- if (!hasMore) return
- updatePage(page + 1)
- }
useEffect(() => {
setTimeout(() => {
if (keyword) {
@@ -59,36 +43,7 @@ export const LayoutSearch = props => {
- {postsToShow.map(p => (
-
-
+ {BLOG.POST_LIST_STYLE === 'page' ? : }
-
-
-
- {p.summary}
-
-
- ))}
-
-
-
- {' '}
- {hasMore ? locale.COMMON.MORE : `${locale.COMMON.NO_MORE} 😰`}{' '}
-
-
}
diff --git a/themes/example/components/BlogListPage.js b/themes/example/components/BlogListPage.js
index 5eb89ece..2feab00f 100644
--- a/themes/example/components/BlogListPage.js
+++ b/themes/example/components/BlogListPage.js
@@ -17,35 +17,37 @@ export const BlogListPage = props => {
return
- {posts.map(p => (
-
-
+
+ {posts?.map(p => (
+
+
-
+
-
- {p.summary}
-
- {/* 搜索结果 */}
- {p.results && (
-
- {p.results.map(r => (
- {r}
- ))}
+
+ {p.summary}
- )}
-
- ))}
+ {/* 搜索结果 */}
+ {p.results && (
+
+ {p.results.map(r => (
+ {r}
+ ))}
+
+ )}
+
+ ))}
+
diff --git a/themes/example/components/BlogListScroll.js b/themes/example/components/BlogListScroll.js
index 07da67d3..c9859c0b 100644
--- a/themes/example/components/BlogListScroll.js
+++ b/themes/example/components/BlogListScroll.js
@@ -43,7 +43,7 @@ export const BlogListScroll = props => {
}
})
- return
+ return
{postsToShow.map(p => (
diff --git a/themes/fukasawa/LayoutSearch.js b/themes/fukasawa/LayoutSearch.js
index e4723c41..9329846d 100644
--- a/themes/fukasawa/LayoutSearch.js
+++ b/themes/fukasawa/LayoutSearch.js
@@ -1,5 +1,7 @@
import LayoutBase from './LayoutBase'
+import BLOG from '@/blog.config'
import BlogListPage from './components/BlogListPage'
+import BlogListScroll from './components/BlogListScroll'
import { useRouter } from 'next/router'
import { useEffect } from 'react'
import { isBrowser } from '@/lib/utils'
@@ -18,6 +20,6 @@ export const LayoutSearch = (props) => {
}, 100)
})
return
-
+ {BLOG.POST_LIST_STYLE === 'page' ? : }
}
diff --git a/themes/fukasawa/LayoutTag.js b/themes/fukasawa/LayoutTag.js
index 8593783e..3a546fad 100644
--- a/themes/fukasawa/LayoutTag.js
+++ b/themes/fukasawa/LayoutTag.js
@@ -1,8 +1,10 @@
+import BLOG from '@/blog.config'
import BlogListPage from './components/BlogListPage'
+import BlogListScroll from './components/BlogListScroll'
import LayoutBase from './LayoutBase'
export const LayoutTag = (props) => {
return
-
+ {BLOG.POST_LIST_STYLE === 'page' ? : }
}
diff --git a/themes/fukasawa/components/BlogListPage.js b/themes/fukasawa/components/BlogListPage.js
index 47650b5b..98dfedff 100644
--- a/themes/fukasawa/components/BlogListPage.js
+++ b/themes/fukasawa/components/BlogListPage.js
@@ -39,9 +39,9 @@ const BlogListPage = ({ page = 1, posts = [], postCount }) => {
return
} else {
return (
-
+
{/* 文章列表 */}
-
+
{posts?.map(post => (
diff --git a/themes/hexo/LayoutSearch.js b/themes/hexo/LayoutSearch.js
index 9f003d2c..6454ef3a 100644
--- a/themes/hexo/LayoutSearch.js
+++ b/themes/hexo/LayoutSearch.js
@@ -1,5 +1,7 @@
import { useRouter } from 'next/router'
import { useEffect, useRef } from 'react'
+import BLOG from '@/blog.config'
+import BlogPostListScroll from './components/BlogPostListScroll'
import BlogPostListPage from './components/BlogPostListPage'
import LayoutBase from './LayoutBase'
import SearchInput from './components/SearchInput'
@@ -25,8 +27,7 @@ export const LayoutSearch = props => {
if (container && container.innerHTML) {
const re = new RegExp(`${currentSearch}`, 'gim')
container.innerHTML = container.innerHTML.replace(
- re,
- `
${currentSearch}`
+ re, `
${currentSearch}`
)
}
}
@@ -34,56 +35,62 @@ export const LayoutSearch = props => {
}, 100)
})
return (
-
-
-
- {/* 分类 */}
-
-
-
- {locale.COMMON.CATEGORY}:
-
-
- {categories?.map(category => {
- return (
-
-
-
- {category.name}({category.count})
-
-
- )
- })}
-
-
- {/* 标签 */}
-
-
-
- {locale.COMMON.TAGS}:
-
-
-
-
-
-
+ >}
+
+ {currentSearch && <>
+
+ {BLOG.POST_LIST_STYLE === 'page' ? : }
+
+ >}
+
+
)
}
diff --git a/themes/medium/LayoutSearch.js b/themes/medium/LayoutSearch.js
index 6aa2ec5a..9a34bcec 100644
--- a/themes/medium/LayoutSearch.js
+++ b/themes/medium/LayoutSearch.js
@@ -3,9 +3,11 @@ import SearchInput from './components/SearchInput'
import { useGlobal } from '@/lib/global'
import TagGroups from './components/TagGroups'
import CategoryGroup from './components/CategoryGroup'
-import BlogPostListScroll from './components/BlogPostListScroll'
import { useEffect } from 'react'
import { isBrowser } from '@/lib/utils'
+import BLOG from '@/blog.config'
+import BlogPostListScroll from './components/BlogPostListScroll'
+import BlogPostListPage from './components/BlogPostListPage'
export const LayoutSearch = (props) => {
const { locale } = useGlobal()
@@ -27,8 +29,8 @@ export const LayoutSearch = (props) => {
-
-
+
+ {BLOG.POST_LIST_STYLE === 'page' ? : }
}
diff --git a/themes/medium/LayoutTag.js b/themes/medium/LayoutTag.js
index dda44141..6f072aa9 100644
--- a/themes/medium/LayoutTag.js
+++ b/themes/medium/LayoutTag.js
@@ -1,6 +1,6 @@
import LayoutBase from './LayoutBase'
-import BlogPostListScroll from './components/BlogPostListScroll'
import BLOG from '@/blog.config'
+import BlogPostListScroll from './components/BlogPostListScroll'
import BlogPostListPage from './components/BlogPostListPage'
export const LayoutTag = (props) => {
diff --git a/themes/medium/components/BlogPostListPage.js b/themes/medium/components/BlogPostListPage.js
index fe91b9b0..ad78969b 100644
--- a/themes/medium/components/BlogPostListPage.js
+++ b/themes/medium/components/BlogPostListPage.js
@@ -18,11 +18,13 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount }) => {
return
} else {
return (
-
+
+
{/* 文章列表 */}
{posts.map(post => (
))}
+
)
diff --git a/themes/next/LayoutSearch.js b/themes/next/LayoutSearch.js
index b1e0be2f..d4ec1bb8 100644
--- a/themes/next/LayoutSearch.js
+++ b/themes/next/LayoutSearch.js
@@ -1,8 +1,10 @@
import LayoutBase from './LayoutBase'
import StickyBar from './components/StickyBar'
-import BlogPostListScroll from './components/BlogPostListScroll'
import { useGlobal } from '@/lib/global'
import { isBrowser } from '@/lib/utils'
+import BlogPostListScroll from './components/BlogPostListScroll'
+import BlogPostListPage from './components/BlogPostListPage'
+import BLOG from '@/blog.config'
export const LayoutSearch = (props) => {
const { locale } = useGlobal()
@@ -23,8 +25,10 @@ export const LayoutSearch = (props) => {
-
-
+ {BLOG.POST_LIST_STYLE !== 'page'
+ ?
+ :
+ }
)
}
diff --git a/themes/next/LayoutTag.js b/themes/next/LayoutTag.js
index 7594ba8c..fdb47239 100644
--- a/themes/next/LayoutTag.js
+++ b/themes/next/LayoutTag.js
@@ -9,14 +9,14 @@ export const LayoutTag = (props) => {
const { tags, tag } = props
return
-
-
-
-
- {BLOG.POST_LIST_STYLE !== 'page'
- ?
- :
- }
-
-
+
+
+
+
+ {BLOG.POST_LIST_STYLE !== 'page'
+ ?
+ :
+ }
+
+
}
diff --git a/themes/next/components/BlogPostListPage.js b/themes/next/components/BlogPostListPage.js
index ac252d8e..6d10433b 100644
--- a/themes/next/components/BlogPostListPage.js
+++ b/themes/next/components/BlogPostListPage.js
@@ -18,9 +18,9 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount }) => {
return
} else {
return (
-
+
{/* 文章列表 */}
-
+
{posts.map(post => (
))}
diff --git a/themes/next/components/BlogPostListScroll.js b/themes/next/components/BlogPostListScroll.js
index d3b78fa6..5fb8e274 100644
--- a/themes/next/components/BlogPostListScroll.js
+++ b/themes/next/components/BlogPostListScroll.js
@@ -52,10 +52,10 @@ const BlogPostListScroll = ({ posts = [], currentSearch, showSummary = CONFIG_NE
if (!postsToShow || postsToShow.length === 0) {
return
} else {
- return
+ return
{/* 文章列表 */}
-
+
{postsToShow.map(post => (
))}
diff --git a/themes/next/components/PaginationNumber.js b/themes/next/components/PaginationNumber.js
index b74bc550..75f048cf 100644
--- a/themes/next/components/PaginationNumber.js
+++ b/themes/next/components/PaginationNumber.js
@@ -1,4 +1,3 @@
-import BLOG from '@/blog.config'
import Link from 'next/link'
import { useRouter } from 'next/router'
@@ -13,79 +12,78 @@ const PaginationNumber = ({ page, totalPage }) => {
const router = useRouter()
const currentPage = +page
const showNext = page !== totalPage
- const pages = generatePages(page, currentPage, totalPage)
+ const pagePrefix = router.asPath.replace(/\/page\/[1-9]\d*/, '').replace(/\/$/, '')
+ const pages = generatePages(pagePrefix, page, currentPage, totalPage)
return (
-
- {/* 上一页 */}
-
-
-
-
-
+
+ {/* 上一页 */}
+
+
+
+
+
- {pages}
+ {pages}
- {/* 下一页 */}
-
-
-
+ {/* 下一页 */}
+
+
+
+
+
-
-
)
}
-function getPageElement(page, currentPage) {
+function getPageElement(pagePrefix, page, currentPage) {
+ console.log(pagePrefix, page, currentPage)
+
return (
-
-
- {page}
-
-
+
+
+ {page}
+
+
)
}
-function generatePages(page, currentPage, totalPage) {
+function generatePages(pagePrefix, page, currentPage, totalPage) {
const pages = []
const groupCount = 7 // 最多显示页签数
if (totalPage <= groupCount) {
for (let i = 1; i <= totalPage; i++) {
- pages.push(getPageElement(i, page))
+ pages.push(getPageElement(pagePrefix, i, page))
}
} else {
- pages.push(getPageElement(1, page))
+ pages.push(getPageElement(pagePrefix, 1, page))
const dynamicGroupCount = groupCount - 2
let startPage = currentPage - 2
if (startPage <= 1) {
@@ -100,7 +98,7 @@ function generatePages(page, currentPage, totalPage) {
for (let i = 0; i < dynamicGroupCount; i++) {
if (startPage + i < totalPage) {
- pages.push(getPageElement(startPage + i, page))
+ pages.push(getPageElement(pagePrefix, startPage + i, page))
}
}
@@ -108,7 +106,7 @@ function generatePages(page, currentPage, totalPage) {
pages.push(
...
)
}
- pages.push(getPageElement(totalPage, page))
+ pages.push(getPageElement(pagePrefix, totalPage, page))
}
return pages
}