mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-06-07 23:16:52 +00:00
movie 404
This commit is contained in:
@@ -25,10 +25,7 @@ export { getPost } from '../notion/getNotionPost'
|
|||||||
* @returns
|
* @returns
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export async function getGlobalData({
|
export async function getGlobalData({ pageId = BLOG.NOTION_PAGE_ID, from }) {
|
||||||
pageId = BLOG.NOTION_PAGE_ID,
|
|
||||||
from
|
|
||||||
}) {
|
|
||||||
// 从notion获取
|
// 从notion获取
|
||||||
const data = await getNotionPageData({ pageId, from })
|
const data = await getNotionPageData({ pageId, from })
|
||||||
const db = deepClone(data)
|
const db = deepClone(data)
|
||||||
@@ -89,7 +86,9 @@ function cleanBlock(post) {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function getLatestPosts({ allPages, from, latestPostCount }) {
|
function getLatestPosts({ allPages, from, latestPostCount }) {
|
||||||
const allPosts = allPages?.filter(page => page.type === 'Post' && page.status === 'Published')
|
const allPosts = allPages?.filter(
|
||||||
|
page => page.type === 'Post' && page.status === 'Published'
|
||||||
|
)
|
||||||
|
|
||||||
const latestPosts = Object.create(allPosts).sort((a, b) => {
|
const latestPosts = Object.create(allPosts).sort((a, b) => {
|
||||||
const dateA = new Date(a?.lastEditedDate || a?.publishDate)
|
const dateA = new Date(a?.lastEditedDate || a?.publishDate)
|
||||||
@@ -140,7 +139,13 @@ function getCustomNav({ allPages }) {
|
|||||||
p.to = '/' + p.slug
|
p.to = '/' + p.slug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customNav.push({ icon: p.icon || null, name: p.title, to: p.slug, target: '_blank', show: true })
|
customNav.push({
|
||||||
|
icon: p.icon || null,
|
||||||
|
name: p.title,
|
||||||
|
to: p.slug,
|
||||||
|
target: '_blank',
|
||||||
|
show: true
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return customNav
|
return customNav
|
||||||
@@ -152,7 +157,12 @@ function getCustomNav({ allPages }) {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function getCustomMenu({ collectionData }) {
|
function getCustomMenu({ collectionData }) {
|
||||||
const menuPages = collectionData.filter(post => post.status === 'Published' && (post?.type === BLOG.NOTION_PROPERTY_NAME.type_menu || post?.type === BLOG.NOTION_PROPERTY_NAME.type_sub_menu))
|
const menuPages = collectionData.filter(
|
||||||
|
post =>
|
||||||
|
post.status === 'Published' &&
|
||||||
|
(post?.type === BLOG.NOTION_PROPERTY_NAME.type_menu ||
|
||||||
|
post?.type === BLOG.NOTION_PROPERTY_NAME.type_sub_menu)
|
||||||
|
)
|
||||||
const menus = []
|
const menus = []
|
||||||
if (menuPages && menuPages.length > 0) {
|
if (menuPages && menuPages.length > 0) {
|
||||||
menuPages.forEach(e => {
|
menuPages.forEach(e => {
|
||||||
@@ -190,7 +200,9 @@ function getCustomMenu({ collectionData }) {
|
|||||||
*/
|
*/
|
||||||
function getTagOptions(schema) {
|
function getTagOptions(schema) {
|
||||||
if (!schema) return {}
|
if (!schema) return {}
|
||||||
const tagSchema = Object.values(schema).find(e => e.name === BLOG.NOTION_PROPERTY_NAME.tags)
|
const tagSchema = Object.values(schema).find(
|
||||||
|
e => e.name === BLOG.NOTION_PROPERTY_NAME.tags
|
||||||
|
)
|
||||||
return tagSchema?.options || []
|
return tagSchema?.options || []
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +213,9 @@ function getTagOptions(schema) {
|
|||||||
*/
|
*/
|
||||||
function getCategoryOptions(schema) {
|
function getCategoryOptions(schema) {
|
||||||
if (!schema) return {}
|
if (!schema) return {}
|
||||||
const categorySchema = Object.values(schema).find(e => e.name === BLOG.NOTION_PROPERTY_NAME.category)
|
const categorySchema = Object.values(schema).find(
|
||||||
|
e => e.name === BLOG.NOTION_PROPERTY_NAME.category
|
||||||
|
)
|
||||||
return categorySchema?.options || []
|
return categorySchema?.options || []
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,9 +227,15 @@ function getCategoryOptions(schema) {
|
|||||||
*/
|
*/
|
||||||
function getSiteInfo({ collection, block }) {
|
function getSiteInfo({ collection, block }) {
|
||||||
const title = collection?.name?.[0][0] || BLOG.TITLE
|
const title = collection?.name?.[0][0] || BLOG.TITLE
|
||||||
const description = collection?.description ? Object.assign(collection).description[0][0] : BLOG.DESCRIPTION
|
const description = collection?.description
|
||||||
const pageCover = collection?.cover ? mapImgUrl(collection?.cover, block[idToUuid(BLOG.NOTION_PAGE_ID)]?.value) : BLOG.HOME_BANNER_IMAGE
|
? Object.assign(collection).description[0][0]
|
||||||
let icon = collection?.icon ? mapImgUrl(collection?.icon, collection, 'collection') : BLOG.AVATAR
|
: BLOG.DESCRIPTION
|
||||||
|
const pageCover = collection?.cover
|
||||||
|
? mapImgUrl(collection?.cover, block[idToUuid(BLOG.NOTION_PAGE_ID)]?.value)
|
||||||
|
: BLOG.HOME_BANNER_IMAGE
|
||||||
|
let icon = collection?.icon
|
||||||
|
? mapImgUrl(collection?.icon, collection, 'collection')
|
||||||
|
: BLOG.AVATAR
|
||||||
|
|
||||||
// 用户头像压缩一下
|
// 用户头像压缩一下
|
||||||
icon = compressImage(icon)
|
icon = compressImage(icon)
|
||||||
@@ -236,7 +256,13 @@ function getSiteInfo({ collection, block }) {
|
|||||||
*/
|
*/
|
||||||
export function getNavPages({ allPages }) {
|
export function getNavPages({ allPages }) {
|
||||||
const allNavPages = allPages?.filter(post => {
|
const allNavPages = allPages?.filter(post => {
|
||||||
return post && post?.slug && (!post?.slug?.startsWith('http')) && post?.type === 'Post' && post?.status === 'Published'
|
return (
|
||||||
|
post &&
|
||||||
|
post?.slug &&
|
||||||
|
!post?.slug?.startsWith('http') &&
|
||||||
|
post?.type === 'Post' &&
|
||||||
|
post?.status === 'Published'
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
return allNavPages.map(item => ({
|
return allNavPages.map(item => ({
|
||||||
@@ -248,7 +274,8 @@ export function getNavPages({ allPages }) {
|
|||||||
summary: item.summary || null,
|
summary: item.summary || null,
|
||||||
slug: item.slug,
|
slug: item.slug,
|
||||||
pageIcon: item.pageIcon || '',
|
pageIcon: item.pageIcon || '',
|
||||||
lastEditedDate: item.lastEditedDate
|
lastEditedDate: item.lastEditedDate,
|
||||||
|
publishDate: item.publishDate
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,19 +292,26 @@ async function getNotice(post) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 没有数据时返回
|
// 没有数据时返回
|
||||||
const EmptyData = (pageId) => {
|
const EmptyData = pageId => {
|
||||||
const empty = {
|
const empty = {
|
||||||
notice: null,
|
notice: null,
|
||||||
siteInfo: getSiteInfo({}),
|
siteInfo: getSiteInfo({}),
|
||||||
allPages: [{
|
allPages: [
|
||||||
id: 1,
|
{
|
||||||
title: `无法获取Notion数据,请检查Notion_ID: \n 当前 ${pageId}`,
|
id: 1,
|
||||||
summary: '访问文档获取帮助→ https://tangly1024.com/article/vercel-deploy-notion-next',
|
title: `无法获取Notion数据,请检查Notion_ID: \n 当前 ${pageId}`,
|
||||||
status: 'Published',
|
summary:
|
||||||
type: 'Post',
|
'访问文档获取帮助→ https://tangly1024.com/article/vercel-deploy-notion-next',
|
||||||
slug: '13a171332816461db29d50e9f575b00d',
|
status: 'Published',
|
||||||
date: { start_date: '2023-04-24', lastEditedDay: '2023-04-24', tagItems: [] }
|
type: 'Post',
|
||||||
}],
|
slug: '13a171332816461db29d50e9f575b00d',
|
||||||
|
date: {
|
||||||
|
start_date: '2023-04-24',
|
||||||
|
lastEditedDay: '2023-04-24',
|
||||||
|
tagItems: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
allNavPages: [],
|
allNavPages: [],
|
||||||
collection: [],
|
collection: [],
|
||||||
collectionQuery: {},
|
collectionQuery: {},
|
||||||
@@ -313,7 +347,8 @@ async function getDataBaseInfoByNotionAPI({ pageId, from }) {
|
|||||||
const rawMetadata = block[pageId]?.value
|
const rawMetadata = block[pageId]?.value
|
||||||
// Check Type Page-Database和Inline-Database
|
// Check Type Page-Database和Inline-Database
|
||||||
if (
|
if (
|
||||||
rawMetadata?.type !== 'collection_view_page' && rawMetadata?.type !== 'collection_view'
|
rawMetadata?.type !== 'collection_view_page' &&
|
||||||
|
rawMetadata?.type !== 'collection_view'
|
||||||
) {
|
) {
|
||||||
console.error(`pageId "${pageId}" is not a database`)
|
console.error(`pageId "${pageId}" is not a database`)
|
||||||
return EmptyData(pageId)
|
return EmptyData(pageId)
|
||||||
@@ -328,9 +363,21 @@ async function getDataBaseInfoByNotionAPI({ pageId, from }) {
|
|||||||
const viewIds = rawMetadata?.view_ids
|
const viewIds = rawMetadata?.view_ids
|
||||||
const collectionData = []
|
const collectionData = []
|
||||||
|
|
||||||
const pageIds = getAllPageIds(collectionQuery, collectionId, collectionView, viewIds)
|
const pageIds = getAllPageIds(
|
||||||
|
collectionQuery,
|
||||||
|
collectionId,
|
||||||
|
collectionView,
|
||||||
|
viewIds
|
||||||
|
)
|
||||||
if (pageIds?.length === 0) {
|
if (pageIds?.length === 0) {
|
||||||
console.error('获取到的文章列表为空,请检查notion模板', collectionQuery, collection, collectionView, viewIds, pageRecordMap)
|
console.error(
|
||||||
|
'获取到的文章列表为空,请检查notion模板',
|
||||||
|
collectionQuery,
|
||||||
|
collection,
|
||||||
|
collectionView,
|
||||||
|
viewIds,
|
||||||
|
pageRecordMap
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
// console.log('有效Page数量', pageIds?.length)
|
// console.log('有效Page数量', pageIds?.length)
|
||||||
}
|
}
|
||||||
@@ -343,7 +390,14 @@ async function getDataBaseInfoByNotionAPI({ pageId, from }) {
|
|||||||
// 如果找不到文章对应的block,说明发生了溢出,使用pageID再去请求
|
// 如果找不到文章对应的block,说明发生了溢出,使用pageID再去请求
|
||||||
const pageBlock = await getSingleBlock(id, from)
|
const pageBlock = await getSingleBlock(id, from)
|
||||||
if (pageBlock.block[id].value) {
|
if (pageBlock.block[id].value) {
|
||||||
const properties = (await getPageProperties(id, pageBlock.block[id].value, schema, null, getTagOptions(schema))) || null
|
const properties =
|
||||||
|
(await getPageProperties(
|
||||||
|
id,
|
||||||
|
pageBlock.block[id].value,
|
||||||
|
schema,
|
||||||
|
null,
|
||||||
|
getTagOptions(schema)
|
||||||
|
)) || null
|
||||||
if (properties) {
|
if (properties) {
|
||||||
collectionData.push(properties)
|
collectionData.push(properties)
|
||||||
}
|
}
|
||||||
@@ -351,7 +405,14 @@ async function getDataBaseInfoByNotionAPI({ pageId, from }) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
const properties = (await getPageProperties(id, value, schema, null, getTagOptions(schema))) || null
|
const properties =
|
||||||
|
(await getPageProperties(
|
||||||
|
id,
|
||||||
|
value,
|
||||||
|
schema,
|
||||||
|
null,
|
||||||
|
getTagOptions(schema)
|
||||||
|
)) || null
|
||||||
if (properties) {
|
if (properties) {
|
||||||
collectionData.push(properties)
|
collectionData.push(properties)
|
||||||
}
|
}
|
||||||
@@ -365,13 +426,16 @@ async function getDataBaseInfoByNotionAPI({ pageId, from }) {
|
|||||||
if (post?.type === 'Post' && post.status === 'Published') {
|
if (post?.type === 'Post' && post.status === 'Published') {
|
||||||
postCount++
|
postCount++
|
||||||
}
|
}
|
||||||
return post && post?.slug &&
|
return (
|
||||||
(!post?.slug?.startsWith('http')) &&
|
post &&
|
||||||
|
post?.slug &&
|
||||||
|
!post?.slug?.startsWith('http') &&
|
||||||
(post?.status === 'Invisible' || post?.status === 'Published')
|
(post?.status === 'Invisible' || post?.status === 'Published')
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 站点配置优先读取配置表格,否则读取blog.config.js 文件
|
// 站点配置优先读取配置表格,否则读取blog.config.js 文件
|
||||||
const NOTION_CONFIG = await getConfigMapFromConfigPage(collectionData) || {}
|
const NOTION_CONFIG = (await getConfigMapFromConfigPage(collectionData)) || {}
|
||||||
|
|
||||||
// Sort by date
|
// Sort by date
|
||||||
if (BLOG.POSTS_SORT_BY === 'date') {
|
if (BLOG.POSTS_SORT_BY === 'date') {
|
||||||
@@ -380,13 +444,27 @@ async function getDataBaseInfoByNotionAPI({ pageId, from }) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const notice = await getNotice(collectionData.filter(post => {
|
const notice = await getNotice(
|
||||||
return post && post?.type && post?.type === 'Notice' && post.status === 'Published'
|
collectionData.filter(post => {
|
||||||
})?.[0])
|
return (
|
||||||
const categoryOptions = getAllCategories({ allPages, categoryOptions: getCategoryOptions(schema) })
|
post &&
|
||||||
|
post?.type &&
|
||||||
|
post?.type === 'Notice' &&
|
||||||
|
post.status === 'Published'
|
||||||
|
)
|
||||||
|
})?.[0]
|
||||||
|
)
|
||||||
|
const categoryOptions = getAllCategories({
|
||||||
|
allPages,
|
||||||
|
categoryOptions: getCategoryOptions(schema)
|
||||||
|
})
|
||||||
const tagOptions = getAllTags({ allPages, tagOptions: getTagOptions(schema) })
|
const tagOptions = getAllTags({ allPages, tagOptions: getTagOptions(schema) })
|
||||||
// 旧的菜单
|
// 旧的菜单
|
||||||
const customNav = getCustomNav({ allPages: collectionData.filter(post => post?.type === 'Page' && post.status === 'Published') })
|
const customNav = getCustomNav({
|
||||||
|
allPages: collectionData.filter(
|
||||||
|
post => post?.type === 'Page' && post.status === 'Published'
|
||||||
|
)
|
||||||
|
})
|
||||||
// 新的菜单
|
// 新的菜单
|
||||||
const customMenu = await getCustomMenu({ collectionData })
|
const customMenu = await getCustomMenu({ collectionData })
|
||||||
const latestPosts = getLatestPosts({ allPages, from, latestPostCount: 6 })
|
const latestPosts = getLatestPosts({ allPages, from, latestPostCount: 6 })
|
||||||
|
|||||||
38
themes/movie/components/ArchiveDateList.js
Normal file
38
themes/movie/components/ArchiveDateList.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { useGlobal } from '@/lib/global'
|
||||||
|
import { formatDateFmt } from '@/lib/utils/formatDate'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
export default function ArchiveDateList(props) {
|
||||||
|
const postsSortByDate = Object.create(props.allNavPages)
|
||||||
|
const { locale } = useGlobal()
|
||||||
|
|
||||||
|
postsSortByDate.sort((a, b) => {
|
||||||
|
return b?.publishDate - a?.publishDate
|
||||||
|
})
|
||||||
|
|
||||||
|
let dates = []
|
||||||
|
postsSortByDate.forEach(post => {
|
||||||
|
const date = formatDateFmt(post.publishDate, 'yyyy-MM')
|
||||||
|
if (!dates[date]) {
|
||||||
|
dates.push(date)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
dates = dates.slice(0, 5)
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="text-2xl dark:text-white mb-2">{locale.NAV.ARCHIVE}</div>
|
||||||
|
{dates?.map((date, index) => {
|
||||||
|
return (
|
||||||
|
<div key={index}>
|
||||||
|
<Link
|
||||||
|
href={`/archive#${date}`}
|
||||||
|
className="hover:underline dark:text-green-500"
|
||||||
|
>
|
||||||
|
{date}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
43
themes/movie/components/CategoryGroup.js
Normal file
43
themes/movie/components/CategoryGroup.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { siteConfig } from '@/lib/config'
|
||||||
|
import { useGlobal } from '@/lib/global'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
const CategoryGroup = props => {
|
||||||
|
const { currentCategory, categoryOptions } = props
|
||||||
|
const { locale } = useGlobal()
|
||||||
|
if (!categoryOptions || categoryOptions.length === 0) return <></>
|
||||||
|
const categoryCount = siteConfig('PREVIEW_CATEGORY_COUNT')
|
||||||
|
const categories = categoryOptions.slice(0, categoryCount)
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<h2 className="text-2xl dark:text-white">{locale.COMMON.CATEGORY}</h2>
|
||||||
|
<div id="category-list" className="dark:border-gray-600 flex flex-col">
|
||||||
|
{categories.map(category => {
|
||||||
|
const selected = currentCategory === category.name
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
key={category.name}
|
||||||
|
href={`/category/${category.name}`}
|
||||||
|
passHref
|
||||||
|
className={
|
||||||
|
(selected
|
||||||
|
? 'hover:text-white dark:hover:text-white bg-gray-600 text-white '
|
||||||
|
: 'dark:text-green-400 text-gray-500 hover:text-white hover:bg-gray-500 dark:hover:text-white') +
|
||||||
|
' w-full items-center duration-300 px-2 cursor-pointer py-1 font-light'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className={`${selected ? 'text-white fa-folder-open ' : 'text-gray-500 fa-folder '} mr-2 fas`}
|
||||||
|
/>
|
||||||
|
{category.name}({category.count})
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CategoryGroup
|
||||||
@@ -8,7 +8,7 @@ import { MenuListTop } from './MenuListTop'
|
|||||||
*/
|
*/
|
||||||
export const Header = props => {
|
export const Header = props => {
|
||||||
return (
|
return (
|
||||||
<header className="w-full px-6 relative z-10">
|
<header className="w-full px-8 relative z-20">
|
||||||
<div className="mx-auto md:flex justify-between items-center">
|
<div className="mx-auto md:flex justify-between items-center">
|
||||||
<Link
|
<Link
|
||||||
href="/"
|
href="/"
|
||||||
@@ -17,7 +17,7 @@ export const Header = props => {
|
|||||||
{siteConfig('TITLE')}
|
{siteConfig('TITLE')}
|
||||||
</Link>
|
</Link>
|
||||||
<div className="w-full md:w-auto text-center md:text-right">
|
<div className="w-full md:w-auto text-center md:text-right">
|
||||||
{/* 右侧文字 */}
|
{/* 右侧菜单 */}
|
||||||
<MenuListTop {...props} />
|
<MenuListTop {...props} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
62
themes/movie/components/LatestPostsGroup.js
Normal file
62
themes/movie/components/LatestPostsGroup.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import { siteConfig } from '@/lib/config'
|
||||||
|
import { useGlobal } from '@/lib/global'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最新文章列表
|
||||||
|
* @param posts 所有文章数据
|
||||||
|
* @param sliceCount 截取展示的数量 默认6
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
const LatestPostsGroup = ({ latestPosts }) => {
|
||||||
|
// 获取当前路径
|
||||||
|
const currentPath = useRouter().asPath
|
||||||
|
const { locale } = useGlobal()
|
||||||
|
|
||||||
|
if (!latestPosts) {
|
||||||
|
return <></>
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="pb-1 px-2 flex flex-nowrap justify-between">
|
||||||
|
<div className="text-2xl text-gray-600 dark:text-gray-200">
|
||||||
|
<i className="mr-2 fas fa-history" />
|
||||||
|
{locale.COMMON.LATEST_POSTS}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{latestPosts.map(post => {
|
||||||
|
const selected =
|
||||||
|
currentPath === `${siteConfig('SUB_PATH', '')}/${post.slug}`
|
||||||
|
const url = checkContainHttp(post.slug)
|
||||||
|
? sliceUrlFromHttp(post.slug)
|
||||||
|
: `${siteConfig('SUB_PATH', '')}/${post.slug}`
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
key={post.id}
|
||||||
|
title={post.title}
|
||||||
|
href={url}
|
||||||
|
passHref
|
||||||
|
className={'my-1 flex'}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
(selected
|
||||||
|
? 'text-white bg-gray-600 '
|
||||||
|
: 'text-gray-500 dark:text-green-400 ') +
|
||||||
|
' py-1 flex hover:bg-gray-500 px-2 duration-200 w-full ' +
|
||||||
|
'hover:text-white dark:hover:text-white cursor-pointer'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<li className="line-clamp-2">{post.title}</li>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default LatestPostsGroup
|
||||||
@@ -40,19 +40,19 @@ export const MenuItemDrop = ({ link }) => {
|
|||||||
{hasSubMenu && (
|
{hasSubMenu && (
|
||||||
<ul
|
<ul
|
||||||
style={{ backdropFilter: 'blur(3px)' }}
|
style={{ backdropFilter: 'blur(3px)' }}
|
||||||
className={`${show ? 'visible opacity-100 top-12' : 'invisible opacity-0 top-20'} drop-shadow-md overflow-hidden rounded-md text-black dark:text-white bg-white dark:bg-black transition-all duration-300 z-30 absolute block `}
|
className={`${show ? 'visible opacity-100 top-14' : 'invisible opacity-0 top-20'} drop-shadow-md overflow-hidden rounded-md text-black dark:text-white bg-white dark:bg-black transition-all duration-300 z-30 absolute block `}
|
||||||
>
|
>
|
||||||
{link.subMenus.map((sLink, index) => {
|
{link.subMenus.map((sLink, index) => {
|
||||||
return (
|
return (
|
||||||
<li
|
<li
|
||||||
key={index}
|
key={index}
|
||||||
className="cursor-pointer hover:bg-indigo-300 hover:text-black tracking-widest transition-all duration-200 dark:border-gray-800 py-1 pr-6 pl-3"
|
className="cursor-pointer dark:bg-hexo-black-gray dark:hover:bg-gray-300 hover:bg-gray-300 hover:text-black tracking-widest transition-all duration-200 dark:border-gray-800 py-1 pr-6 pl-3"
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={sLink.to}
|
href={sLink.to}
|
||||||
target={link?.to?.indexOf('http') === 0 ? '_blank' : '_self'}
|
target={link?.to?.indexOf('http') === 0 ? '_blank' : '_self'}
|
||||||
>
|
>
|
||||||
<span className="text-sm text-nowrap font-extralight">
|
<span className="text-sm text-nowrap">
|
||||||
{link?.icon && <i className={sLink?.icon}> </i>}
|
{link?.icon && <i className={sLink?.icon}> </i>}
|
||||||
{sLink.title}
|
{sLink.title}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -3,14 +3,32 @@ import CONFIG from '../config'
|
|||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
import { MenuItemDrop } from './MenuItemDrop'
|
import { MenuItemDrop } from './MenuItemDrop'
|
||||||
|
|
||||||
export const MenuListTop = (props) => {
|
export const MenuListTop = props => {
|
||||||
const { customNav, customMenu } = props
|
const { customNav, customMenu } = props
|
||||||
const { locale } = useGlobal()
|
const { locale } = useGlobal()
|
||||||
|
|
||||||
let links = [
|
let links = [
|
||||||
{ id: 1, icon: 'fa-solid fa-house', name: locale.NAV.INDEX, to: '/', show: siteConfig('HEXO_MENU_INDEX', null, CONFIG) },
|
{
|
||||||
{ id: 2, icon: 'fas fa-search', name: locale.NAV.SEARCH, to: '/search', show: siteConfig('HEXO_MENU_SEARCH', null, CONFIG) },
|
id: 1,
|
||||||
{ id: 3, icon: 'fas fa-archive', name: locale.NAV.ARCHIVE, to: '/archive', show: siteConfig('HEXO_MENU_ARCHIVE', null, CONFIG) }
|
icon: 'fa-solid fa-house',
|
||||||
|
name: locale.NAV.INDEX,
|
||||||
|
to: '/',
|
||||||
|
show: siteConfig('HEXO_MENU_INDEX', null, CONFIG)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
icon: 'fas fa-search',
|
||||||
|
name: locale.NAV.SEARCH,
|
||||||
|
to: '/search',
|
||||||
|
show: siteConfig('HEXO_MENU_SEARCH', null, CONFIG)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
icon: 'fas fa-archive',
|
||||||
|
name: locale.NAV.ARCHIVE,
|
||||||
|
to: '/archive',
|
||||||
|
show: siteConfig('HEXO_MENU_ARCHIVE', null, CONFIG)
|
||||||
|
}
|
||||||
// { icon: 'fas fa-folder', name: locale.COMMON.CATEGORY, to: '/category', show: siteConfig('MENU_CATEGORY', null, CONFIG) },
|
// { icon: 'fas fa-folder', name: locale.COMMON.CATEGORY, to: '/category', show: siteConfig('MENU_CATEGORY', null, CONFIG) },
|
||||||
// { icon: 'fas fa-tag', name: locale.COMMON.TAGS, to: '/tag', show: siteConfig('MENU_TAG', null, CONFIG) }
|
// { icon: 'fas fa-tag', name: locale.COMMON.TAGS, to: '/tag', show: siteConfig('MENU_TAG', null, CONFIG) }
|
||||||
]
|
]
|
||||||
@@ -34,9 +52,14 @@ export const MenuListTop = (props) => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return (<>
|
return (
|
||||||
<nav id='nav-mobile' className='leading-8 justify-center font-light w-full flex'>
|
<>
|
||||||
{links?.map((link, index) => link && link.show && <MenuItemDrop key={index} link={link} />)}
|
<nav id="nav-mobile" className="leading-8 justify-center w-full flex">
|
||||||
</nav>
|
{links?.map(
|
||||||
</>)
|
(link, index) =>
|
||||||
|
link && link.show && <MenuItemDrop key={index} link={link} />
|
||||||
|
)}
|
||||||
|
</nav>
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
51
themes/movie/components/TagGroups.js
Normal file
51
themes/movie/components/TagGroups.js
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import { useGlobal } from '@/lib/global'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标签组
|
||||||
|
* @param tags
|
||||||
|
* @param currentTag
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
const TagGroups = ({ tagOptions, className }) => {
|
||||||
|
const router = useRouter()
|
||||||
|
const { locale } = useGlobal()
|
||||||
|
const { tag: currentTag } = router.query
|
||||||
|
if (!tagOptions) return <></>
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="text-2xl dark:text-white mb-2">{locale.COMMON.TAGS}</div>
|
||||||
|
<div id="tags-group" className="dark:border-gray-700 space-y-2">
|
||||||
|
{tagOptions.map((tag, index) => {
|
||||||
|
const selected = currentTag === tag.name
|
||||||
|
return (
|
||||||
|
<Link
|
||||||
|
passHref
|
||||||
|
key={index}
|
||||||
|
href={`/tag/${encodeURIComponent(tag.name)}`}
|
||||||
|
className={'cursor-pointer inline-block whitespace-nowrap'}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`${className || ''}
|
||||||
|
${selected ? 'text-white bg-blue-600 dark:bg-yellow-600' : ''}
|
||||||
|
flex items-center hover:bg-blue-600 dark:hover:bg-yellow-600 hover:scale-110 hover:text-white rounded-lg px-2 py-0.5 duration-150 transition-all`}
|
||||||
|
>
|
||||||
|
<div className="text-lg">{tag.name} </div>
|
||||||
|
{tag.count ? (
|
||||||
|
<sup className="relative ml-1">{tag.count}</sup>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TagGroups
|
||||||
@@ -6,11 +6,9 @@ const TagItemMini = ({ tag, selected = false }) => {
|
|||||||
key={tag}
|
key={tag}
|
||||||
href={selected ? '/' : `/tag/${encodeURIComponent(tag.name)}`}
|
href={selected ? '/' : `/tag/${encodeURIComponent(tag.name)}`}
|
||||||
passHref
|
passHref
|
||||||
className={
|
className={'inline-block rounded-xl py-0.5 mr-2 text-[#2EBF8B]'}
|
||||||
'inline-block text-md font-extrabold rounded-xl text-shadow py-0.5 mr-2 text-[#2EBF8B]'
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<div className="font-light">
|
<div className="text-md font-bold text-shadow">
|
||||||
{selected && <i className="mr-1 fa-tag" />}{' '}
|
{selected && <i className="mr-1 fa-tag" />}{' '}
|
||||||
{tag.name + (tag.count ? `(${tag.count})` : '')}{' '}
|
{tag.name + (tag.count ? `(${tag.count})` : '')}{' '}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import CONFIG from './config'
|
import CONFIG from './config'
|
||||||
import { useEffect } from 'react'
|
import { createContext, useContext, useEffect, useRef } from 'react'
|
||||||
import { Header } from './components/Header'
|
import { Header } from './components/Header'
|
||||||
import { Nav } from './components/Nav'
|
import { Nav } from './components/Nav'
|
||||||
import { Footer } from './components/Footer'
|
import { Footer } from './components/Footer'
|
||||||
@@ -26,6 +26,16 @@ import { useRouter } from 'next/router'
|
|||||||
import { Transition } from '@headlessui/react'
|
import { Transition } from '@headlessui/react'
|
||||||
import { Style } from './style'
|
import { Style } from './style'
|
||||||
import { siteConfig } from '@/lib/config'
|
import { siteConfig } from '@/lib/config'
|
||||||
|
import AlgoliaSearchModal from '@/components/AlgoliaSearchModal'
|
||||||
|
import LatestPostsGroup from './components/LatestPostsGroup'
|
||||||
|
import CategoryGroup from './components/CategoryGroup'
|
||||||
|
import { formatDateFmt } from '@/lib/utils/formatDate'
|
||||||
|
import ArchiveDateList from './components/ArchiveDateList'
|
||||||
|
import TagGroups from './components/TagGroups'
|
||||||
|
|
||||||
|
// 主题全局状态
|
||||||
|
const ThemeGlobalMovie = createContext()
|
||||||
|
export const useMovieGlobal = () => useContext(ThemeGlobalMovie)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基础布局框架
|
* 基础布局框架
|
||||||
@@ -35,32 +45,11 @@ import { siteConfig } from '@/lib/config'
|
|||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
const LayoutBase = props => {
|
const LayoutBase = props => {
|
||||||
const { children } = props
|
const { children, slotTop } = props
|
||||||
const { onLoading, fullWidth } = useGlobal()
|
const { onLoading, fullWidth } = useGlobal()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { category, tag } = props
|
const { category, tag } = props
|
||||||
// 顶部如果是按照分类或标签查看文章列表,列表顶部嵌入一个横幅
|
const searchModal = useRef(null)
|
||||||
// 如果是搜索,则列表顶部嵌入 搜索框
|
|
||||||
let slotTop = null
|
|
||||||
if (category) {
|
|
||||||
slotTop = (
|
|
||||||
<div className="pb-12">
|
|
||||||
<i className="mr-1 fas fa-folder-open" />
|
|
||||||
{category}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
} else if (tag) {
|
|
||||||
slotTop = <div className="pb-12">#{tag}</div>
|
|
||||||
} else if (props.slotTop) {
|
|
||||||
slotTop = props.slotTop
|
|
||||||
} else if (router.route === '/search') {
|
|
||||||
// 嵌入一个搜索框在顶部
|
|
||||||
slotTop = (
|
|
||||||
<div className="pb-12">
|
|
||||||
<SearchInput {...props} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 增加一个状态以触发 Transition 组件的动画
|
// 增加一个状态以触发 Transition 组件的动画
|
||||||
// const [showTransition, setShowTransition] = useState(true)
|
// const [showTransition, setShowTransition] = useState(true)
|
||||||
@@ -71,58 +60,63 @@ const LayoutBase = props => {
|
|||||||
// }, [onLoading])
|
// }, [onLoading])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<ThemeGlobalMovie.Provider value={{ searchModal }}>
|
||||||
id="theme-example"
|
<div
|
||||||
className={`${siteConfig('FONT_STYLE')} dark:text-gray-300 bg-white dark:bg-[#2A2A2A] scroll-smooth`}
|
id="theme-movie"
|
||||||
>
|
className={`${siteConfig('FONT_STYLE')} dark:text-gray-300 bg-white dark:bg-[#2A2A2A] scroll-smooth min-h-screen flex flex-col justify-between`}
|
||||||
<Style />
|
>
|
||||||
|
<Style />
|
||||||
|
|
||||||
{/* 页头 */}
|
{/* 页头 */}
|
||||||
<Header {...props} />
|
<Header {...props} />
|
||||||
|
|
||||||
{/* 主体 */}
|
{/* 主体 */}
|
||||||
<div id="container-inner" className="w-full relative z-10">
|
<div id="container-inner" className="w-full relative z-10">
|
||||||
{/* 标题栏 */}
|
{/* 标题栏 */}
|
||||||
{/* {fullWidth ? null : <Title {...props} />} */}
|
{/* {fullWidth ? null : <Title {...props} />} */}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
id="container-wrapper"
|
id="container-wrapper"
|
||||||
className={
|
className={
|
||||||
(JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE'))
|
(JSON.parse(siteConfig('LAYOUT_SIDEBAR_REVERSE'))
|
||||||
? 'flex-row-reverse'
|
? 'flex-row-reverse'
|
||||||
: '') +
|
: '') +
|
||||||
'relative mx-auto justify-center md:flex items-start py-8 px-2'
|
'relative mx-auto justify-center md:flex items-start py-8 px-2'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{/* 内容 */}
|
{/* 内容 */}
|
||||||
<div className={`w-full ${fullWidth ? '' : ''} xl:px-32 lg:px-4`}>
|
<div className={`w-full ${fullWidth ? '' : ''} xl:px-32 lg:px-4`}>
|
||||||
<Transition
|
<Transition
|
||||||
show={!onLoading}
|
show={!onLoading}
|
||||||
appear={true}
|
appear={true}
|
||||||
enter="transition ease-in-out duration-700 transform order-first"
|
enter="transition ease-in-out duration-700 transform order-first"
|
||||||
enterFrom="opacity-0 translate-y-16"
|
enterFrom="opacity-0 translate-y-16"
|
||||||
enterTo="opacity-100"
|
enterTo="opacity-100"
|
||||||
leave="transition ease-in-out duration-300 transform"
|
leave="transition ease-in-out duration-300 transform"
|
||||||
leaveFrom="opacity-100 translate-y-0"
|
leaveFrom="opacity-100 translate-y-0"
|
||||||
leaveTo="opacity-0 -translate-y-16"
|
leaveTo="opacity-0 -translate-y-16"
|
||||||
unmount={false}
|
unmount={false}
|
||||||
>
|
>
|
||||||
{/* 嵌入模块 */}
|
{/* 嵌入模块 */}
|
||||||
{slotTop}
|
{slotTop}
|
||||||
{children}
|
{children}
|
||||||
</Transition>
|
</Transition>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 页脚 */}
|
{/* 页脚 */}
|
||||||
<Footer {...props} />
|
<Footer {...props} />
|
||||||
|
|
||||||
{/* 回顶按钮 */}
|
{/* 搜索框 */}
|
||||||
<div className="fixed right-4 bottom-4 z-10">
|
<AlgoliaSearchModal cRef={searchModal} {...props} />
|
||||||
<JumpToTopButton />
|
|
||||||
|
{/* 回顶按钮 */}
|
||||||
|
<div className="fixed right-4 bottom-4 z-10">
|
||||||
|
<JumpToTopButton />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</ThemeGlobalMovie.Provider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +194,55 @@ const LayoutSlug = props => {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const Layout404 = props => {
|
const Layout404 = props => {
|
||||||
return <>404 Not found.</>
|
const { locale } = useGlobal()
|
||||||
|
const { searchModal } = useMovieGlobal()
|
||||||
|
const router = useRouter()
|
||||||
|
// 展示搜索框
|
||||||
|
const toggleShowSearchInput = () => {
|
||||||
|
if (siteConfig('ALGOLIA_APP_ID')) {
|
||||||
|
searchModal.current.openSearch()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onKeyUp = e => {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
const search = document.getElementById('search').value
|
||||||
|
if (search) {
|
||||||
|
router.push({ pathname: '/search/' + search })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="h-52">
|
||||||
|
<h2 className="text-4xl">{locale.COMMON.NO_RESULTS_FOUND}</h2>
|
||||||
|
<hr className="my-4" />
|
||||||
|
<div className="max-w-md relative">
|
||||||
|
<input
|
||||||
|
autoFocus
|
||||||
|
id="search"
|
||||||
|
onClick={toggleShowSearchInput}
|
||||||
|
onKeyUp={onKeyUp}
|
||||||
|
className="float-left w-full outline-none h-full p-2 rounded dark:bg-[#383838] bg-gray-100"
|
||||||
|
aria-label="Submit search"
|
||||||
|
type="search"
|
||||||
|
name="s"
|
||||||
|
autoComplete="off"
|
||||||
|
placeholder="Type then hit enter to search..."
|
||||||
|
/>
|
||||||
|
<i className="fas fa-search absolute right-0 my-auto p-2"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* 底部导航 */}
|
||||||
|
<div className="h-full flex-grow grid grid-cols-4 gap-4">
|
||||||
|
<LatestPostsGroup {...props} />
|
||||||
|
<CategoryGroup {...props} />
|
||||||
|
<ArchiveDateList {...props} />
|
||||||
|
<TagGroups {...props} />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { MenuList } from './MenuList'
|
|||||||
* @param {*} props
|
* @param {*} props
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export default function NavBar (props) {
|
export default function NavBar(props) {
|
||||||
const [showSearchInput, changeShowSearchInput] = useState(false)
|
const [showSearchInput, changeShowSearchInput] = useState(false)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { searchModal } = useSimpleGlobal()
|
const { searchModal } = useSimpleGlobal()
|
||||||
@@ -23,7 +23,7 @@ export default function NavBar (props) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onKeyUp = (e) => {
|
const onKeyUp = e => {
|
||||||
if (e.keyCode === 13) {
|
if (e.keyCode === 13) {
|
||||||
const search = document.getElementById('theme-simple-search').value
|
const search = document.getElementById('theme-simple-search').value
|
||||||
if (search) {
|
if (search) {
|
||||||
@@ -33,19 +33,41 @@ export default function NavBar (props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className="w-full bg-white md:pt-0 relative z-20 shadow border-t border-gray-100 dark:border-hexo-black-gray dark:bg-black">
|
<nav className="w-full bg-white md:pt-0 relative z-20 shadow border-t border-gray-100 dark:border-hexo-black-gray dark:bg-black">
|
||||||
<div id="nav-bar-inner" className="h-12 mx-auto max-w-9/10 justify-between items-center text-sm md:text-md md:justify-start">
|
<div
|
||||||
{/* 左侧菜单 */}
|
id="nav-bar-inner"
|
||||||
<div className="h-full w-full float-left text-center md:text-left flex flex-wrap items-stretch md:justify-start md:items-start space-x-4">
|
className="h-12 mx-auto max-w-9/10 justify-between items-center text-sm md:text-md md:justify-start"
|
||||||
{showSearchInput && <input autoFocus id="theme-simple-search" onKeyUp={onKeyUp} className='float-left w-full outline-none h-full px-4' aria-label="Submit search" type="search" name="s" autoComplete="off" placeholder="Type then hit enter to search..." />}
|
>
|
||||||
{!showSearchInput && (<MenuList {...props}/>)}
|
{/* 左侧菜单 */}
|
||||||
</div>
|
<div className="h-full w-full float-left text-center md:text-left flex flex-wrap items-stretch md:justify-start md:items-start space-x-4">
|
||||||
|
{showSearchInput && (
|
||||||
|
<input
|
||||||
|
autoFocus
|
||||||
|
id="theme-simple-search"
|
||||||
|
onKeyUp={onKeyUp}
|
||||||
|
className="float-left w-full outline-none h-full px-4"
|
||||||
|
aria-label="Submit search"
|
||||||
|
type="search"
|
||||||
|
name="s"
|
||||||
|
autoComplete="off"
|
||||||
|
placeholder="Type then hit enter to search..."
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!showSearchInput && <MenuList {...props} />}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="absolute right-12 h-full text-center px-2 flex items-center text-blue-400 cursor-pointer">
|
<div className="absolute right-12 h-full text-center px-2 flex items-center text-blue-400 cursor-pointer">
|
||||||
{/* <!-- extra links --> */}
|
{/* <!-- extra links --> */}
|
||||||
<i className={showSearchInput ? 'fa-regular fa-circle-xmark' : 'fa-solid fa-magnifying-glass' + ' align-middle'} onClick={toggleShowSearchInput}></i>
|
<i
|
||||||
</div>
|
className={
|
||||||
</div>
|
showSearchInput
|
||||||
</nav>
|
? 'fa-regular fa-circle-xmark'
|
||||||
|
: 'fa-solid fa-magnifying-glass' + ' align-middle'
|
||||||
|
}
|
||||||
|
onClick={toggleShowSearchInput}
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user