diff --git a/themes/movie/components/BlogListPage.js b/themes/movie/components/BlogListPage.js index 450f713b..925156bf 100644 --- a/themes/movie/components/BlogListPage.js +++ b/themes/movie/components/BlogListPage.js @@ -1,35 +1,17 @@ import { siteConfig } from '@/lib/config' -import { useGlobal } from '@/lib/global' -import { useRouter } from 'next/router' -import Link from 'next/link' import CONFIG from '../config' import BlogPostCard from './BlogPostCard' import PaginationNumber from './PaginationNumber' export const BlogListPage = props => { - const { page = 1, posts, postCount } = props - const { locale } = useGlobal() - const router = useRouter() - const totalPage = Math.ceil( - postCount / parseInt(siteConfig('POSTS_PER_PAGE')) - ) - const currentPage = +page - - const showPrev = currentPage > 1 - const showNext = page < totalPage - const pagePrefix = router.asPath - .split('?')[0] - .replace(/\/page\/[1-9]\d*/, '') - .replace(/\/$/, '') - - const showPageCover = siteConfig('EXAMPLE_POST_LIST_COVER', null, CONFIG) + const { posts } = props + const showPageCover = siteConfig('MOVIE_POST_LIST_COVER', null, CONFIG) return (
+ id='posts-wrapper' + className='grid md:grid-cols-2 md:gap-12 lg:grid-cols-3 lg:gap-20 xl:gap-24 2xl:grid-cols-4'> {posts?.map(post => ( ))} diff --git a/themes/movie/components/BlogPostCard.js b/themes/movie/components/BlogPostCard.js index 0fc149e1..6aa84072 100644 --- a/themes/movie/components/BlogPostCard.js +++ b/themes/movie/components/BlogPostCard.js @@ -1,42 +1,36 @@ +import LazyImage from '@/components/LazyImage' +import NotionIcon from '@/components/NotionIcon' import { siteConfig } from '@/lib/config' +import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils' import Link from 'next/link' import TagItemMini from './TagItemMini' -import CONFIG from '../config' -import TwikooCommentCount from '@/components/TwikooCommentCount' -import LazyImage from '@/components/LazyImage' -import { formatDateFmt } from '@/lib/utils/formatDate' -import { checkContainHttp, sliceUrlFromHttp } from '@/lib/utils' -import NotionIcon from '@/components/NotionIcon' const BlogPostCard = ({ index, post, showSummary, siteInfo }) => { // 主题默认强制显示图片 if (post && !post.pageCoverThumbnail) { - post.pageCoverThumbnail = - siteInfo?.pageCover || siteConfig('RANDOM_IMAGE_URL') + post.pageCoverThumbnail = siteInfo?.pageCover || siteConfig('RANDOM_IMAGE_URL') } - const url = checkContainHttp(post.slug) - ? sliceUrlFromHttp(post.slug) - : `${siteConfig('SUB_PATH', '')}/${post.slug}` + const url = checkContainHttp(post.slug) ? sliceUrlFromHttp(post.slug) : `${siteConfig('SUB_PATH', '')}/${post.slug}` return ( -
+
{/* 固定高度 ,空白用图片拉升填充 */} -
+
{/* 图片 填充卡片 */} -
+
-
+
{post?.tagItems && post?.tagItems.length > 0 && ( <> -
+
{post.tagItems.map(tag => ( ))} @@ -45,13 +39,13 @@ const BlogPostCard = ({ index, post, showSummary, siteInfo }) => { )}
{/* 阴影遮罩 */} -

+

{post.title}

-
-
+
+
diff --git a/themes/movie/components/Header.js b/themes/movie/components/Header.js index ae5e3a2a..223df3e5 100644 --- a/themes/movie/components/Header.js +++ b/themes/movie/components/Header.js @@ -1,26 +1,163 @@ import Link from 'next/link' import { siteConfig } from '@/lib/config' -import { MenuListTop } from './MenuListTop' +import { useMovieGlobal } from '..' +import Collapse from '@/components/Collapse' +import { MenuItemCollapse } from './MenuItemCollapse' +import { useGlobal } from '@/lib/global' +import CONFIG from '../config' +import { MenuItemDrop } from './MenuItemDrop' +import { useEffect, useState } from 'react' +import { useRouter } from 'next/router' /** * 网站顶部 * @returns */ export const Header = props => { + const { collapseRef, searchModal } = useMovieGlobal() + const router = useRouter() + const { customNav, customMenu } = props + const { locale } = useGlobal() + const [isOpen, setIsOpen] = useState(false) + const [showSearch, setShowSearch] = useState(false) + const toggleMenuOpen = () => { + setIsOpen(!isOpen) + } + let links = [ + { + id: 1, + icon: 'fa-solid fa-house', + name: locale.NAV.INDEX, + to: '/', + show: siteConfig('MOVIE_MENU_INDEX', null, CONFIG) + }, + { + id: 2, + icon: 'fas fa-search', + name: locale.NAV.SEARCH, + to: '/search', + show: siteConfig('MOVIE_MENU_SEARCH', null, CONFIG) + }, + { + id: 3, + icon: 'fas fa-archive', + name: locale.NAV.ARCHIVE, + to: '/archive', + show: siteConfig('MOVIE_MENU_ARCHIVE', 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) } + ] + + if (customNav) { + links = links.concat(customNav) + } + + for (let i = 0; i < links.length; i++) { + if (links[i].id !== i) { + links[i].id = i + } + } + + // 如果 开启自定义菜单,则覆盖Page生成的菜单 + if (siteConfig('CUSTOM_MENU')) { + links = customMenu + } + + // 展示搜索框 + const toggleShowSearchInput = () => { + if (siteConfig('ALGOLIA_APP_ID')) { + searchModal.current.openSearch() + } else { + setShowSearch(!showSearch) + } + } + + useEffect(() => { + if (showSearch) { + setTimeout(() => { + document.getElementById('search').focus() + }, 100); + } + }, [showSearch]) + + const onKeyUp = e => { + if (e.keyCode === 13) { + const search = document.getElementById('search').value + if (search) { + router.push({ pathname: '/search/' + search }) + } + } + } + + const handleSearch = () => { + const search = document.getElementById('search').value + if (search) { + router.push({ pathname: '/search/' + search }) + } + } + return ( -
-
+ <> +
+ href='/' + className='whitespace-nowrap py-6 text-2xl md:text-3xl font-bold text-gray-dark no-underline flex items-center'> {siteConfig('TITLE')} -
+ +
{/* 右侧菜单 */} - + <> + + +
+ +
+
+ + +
+ + {/* 移动端按钮 */} +
+
+ {isOpen ? : } +
+
+
-
-
+
+ + + {/* 移动端菜单 */} + + {links?.map( + (link, index) => + link && + link.show && ( + collapseRef.current?.updateCollapseHeight(param)} + key={index} + link={link} + /> + ) + )} + + + ) } diff --git a/themes/movie/components/MenuItemCollapse.js b/themes/movie/components/MenuItemCollapse.js new file mode 100644 index 00000000..0f91f1d4 --- /dev/null +++ b/themes/movie/components/MenuItemCollapse.js @@ -0,0 +1,77 @@ +import Collapse from '@/components/Collapse' +import Link from 'next/link' +import { useState } from 'react' + +/** + * 折叠菜单 + * @param {*} param0 + * @returns + */ +export const MenuItemCollapse = props => { + const { link } = props + const [show, changeShow] = useState(false) + const hasSubMenu = link?.subMenus?.length > 0 + + const [isOpen, changeIsOpen] = useState(false) + + const toggleShow = () => { + changeShow(!show) + } + + const toggleOpenSubMenu = () => { + changeIsOpen(!isOpen) + } + + if (!link || !link.show) { + return null + } + + return ( + <> +
+ {!hasSubMenu && ( + + + {link?.icon && } + {link?.name} + + + )} + {hasSubMenu && ( +
+ + {link?.icon && } + {link?.name} + + +
+ )} +
+ + {/* 折叠子菜单 */} + {hasSubMenu && ( + + {link.subMenus.map((sLink, index) => { + return ( +
+ + + {link?.icon && } {sLink.title} + + +
+ ) + })} +
+ )} + + ) +} diff --git a/themes/movie/components/MenuItemDrop.js b/themes/movie/components/MenuItemDrop.js index 501140a4..5d2f8a8d 100644 --- a/themes/movie/components/MenuItemDrop.js +++ b/themes/movie/components/MenuItemDrop.js @@ -18,7 +18,7 @@ export const MenuItemDrop = ({ link }) => { {link?.icon && } {link?.name} {hasSubMenu && } diff --git a/themes/movie/components/MenuListTop.js b/themes/movie/components/MenuListTop.js deleted file mode 100644 index d79b2ab5..00000000 --- a/themes/movie/components/MenuListTop.js +++ /dev/null @@ -1,65 +0,0 @@ -import { useGlobal } from '@/lib/global' -import CONFIG from '../config' -import { siteConfig } from '@/lib/config' -import { MenuItemDrop } from './MenuItemDrop' - -export const MenuListTop = props => { - const { customNav, customMenu } = props - const { locale } = useGlobal() - - 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: 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-tag', name: locale.COMMON.TAGS, to: '/tag', show: siteConfig('MENU_TAG', null, CONFIG) } - ] - - if (customNav) { - links = links.concat(customNav) - } - - for (let i = 0; i < links.length; i++) { - if (links[i].id !== i) { - links[i].id = i - } - } - - // 如果 开启自定义菜单,则覆盖Page生成的菜单 - if (siteConfig('CUSTOM_MENU')) { - links = customMenu - } - - if (!links || links.length === 0) { - return null - } - - return ( - <> - - - ) -} diff --git a/themes/movie/components/Nav.js b/themes/movie/components/Nav.js deleted file mode 100644 index 08f5ca56..00000000 --- a/themes/movie/components/Nav.js +++ /dev/null @@ -1,73 +0,0 @@ -import { siteConfig } from '@/lib/config' -import { useGlobal } from '@/lib/global' -import CONFIG from '../config' -import { MenuItemDrop } from './MenuItemDrop' - -/** - * 菜单导航 - * @param {*} props - * @returns - */ -export const Nav = props => { - const { customNav, customMenu } = props - const { locale } = useGlobal() - - let links = [ - { - id: 1, - icon: 'fas fa-search', - name: locale.NAV.SEARCH, - to: '/search', - show: siteConfig('EXAMPLE_MENU_SEARCH', null, CONFIG) - }, - { - id: 2, - icon: 'fas fa-archive', - name: locale.NAV.ARCHIVE, - to: '/archive', - show: siteConfig('EXAMPLE_MENU_ARCHIVE', null, CONFIG) - }, - { - id: 3, - icon: 'fas fa-folder', - name: locale.COMMON.CATEGORY, - to: '/category', - show: siteConfig('EXAMPLE_MENU_CATEGORY', null, CONFIG) - }, - { - id: 4, - icon: 'fas fa-tag', - name: locale.COMMON.TAGS, - to: '/tag', - show: siteConfig('EXAMPLE_MENU_TAG', null, CONFIG) - } - ] - - if (customNav) { - links = links.concat(customNav) - } - - // 如果 开启自定义菜单,则不再使用 Page生成菜单。 - if (siteConfig('CUSTOM_MENU')) { - links = customMenu - } - - if (!links || links.length === 0) { - return null - } - - return ( - - ) -} diff --git a/themes/movie/config.js b/themes/movie/config.js index 181d3a93..48403075 100644 --- a/themes/movie/config.js +++ b/themes/movie/config.js @@ -3,12 +3,12 @@ */ const CONFIG = { // 菜单配置 - EXAMPLE_MENU_CATEGORY: true, // 显示分类 - EXAMPLE_MENU_TAG: true, // 显示标签 - EXAMPLE_MENU_ARCHIVE: true, // 显示归档 - EXAMPLE_MENU_SEARCH: true, // 显示搜索 + MOVIE_MENU_CATEGORY: true, // 显示分类 + MOVIE_MENU_TAG: true, // 显示标签 + MOVIE_MENU_ARCHIVE: true, // 显示归档 + MOVIE_MENU_SEARCH: true, // 显示搜索 - EXAMPLE_POST_LIST_COVER: true // 列表显示文章封面 + MOVIE_POST_LIST_COVER: true // 列表显示文章封面 } export default CONFIG diff --git a/themes/movie/index.js b/themes/movie/index.js index 2aaa95da..e34f0e83 100644 --- a/themes/movie/index.js +++ b/themes/movie/index.js @@ -1,37 +1,32 @@ 'use client' -import CONFIG from './config' -import { createContext, useContext, useEffect, useRef } from 'react' -import { Header } from './components/Header' -import { Nav } from './components/Nav' -import { Footer } from './components/Footer' -import { Title } from './components/Title' -import { SideBar } from './components/SideBar' +import AlgoliaSearchModal from '@/components/AlgoliaSearchModal' +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 { useRouter } from 'next/router' +import { createContext, useContext, useEffect, useRef, useState } from 'react' +import ArchiveDateList from './components/ArchiveDateList' +import { ArticleInfo } from './components/ArticleInfo' +import { ArticleLock } from './components/ArticleLock' +import BlogListGroupByDate from './components/BlogListGroupByDate' import { BlogListPage } from './components/BlogListPage' import { BlogListScroll } from './components/BlogListScroll' -import { useGlobal } from '@/lib/global' -import { ArticleLock } from './components/ArticleLock' -import { ArticleInfo } from './components/ArticleInfo' -import JumpToTopButton from './components/JumpToTopButton' -import NotionPage from '@/components/NotionPage' -import Comment from '@/components/Comment' -import ShareBar from '@/components/ShareBar' -import SearchInput from './components/SearchInput' -import replaceSearchResult from '@/components/Mark' -import { isBrowser } from '@/lib/utils' -import BlogListGroupByDate from './components/BlogListGroupByDate' -import CategoryItem from './components/CategoryItem' -import TagItem from './components/TagItem' -import { useRouter } from 'next/router' -import { Transition } from '@headlessui/react' -import { Style } from './style' -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 CategoryItem from './components/CategoryItem' +import { Footer } from './components/Footer' +import { Header } from './components/Header' +import JumpToTopButton from './components/JumpToTopButton' +import LatestPostsGroup from './components/LatestPostsGroup' import TagGroups from './components/TagGroups' +import TagItem from './components/TagItem' +import CONFIG from './config' +import { Style } from './style' // 主题全局状态 const ThemeGlobalMovie = createContext() @@ -47,56 +42,44 @@ export const useMovieGlobal = () => useContext(ThemeGlobalMovie) const LayoutBase = props => { const { children, slotTop } = props const { onLoading, fullWidth } = useGlobal() - const router = useRouter() - const { category, tag } = props - const searchModal = useRef(null) + const collapseRef = useRef(null) - // 增加一个状态以触发 Transition 组件的动画 - // const [showTransition, setShowTransition] = useState(true) - // useEffect(() => { - // // 当 location 或 children 发生变化时,触发动画 - // setShowTransition(false) - // setTimeout(() => setShowTransition(true), 5) - // }, [onLoading]) + const searchModal = useRef(null) + const [expandMenu, updateExpandMenu] = useState(false) return ( - +
+ id='theme-movie' + className={`${siteConfig('FONT_STYLE')} dark:text-gray-300 duration-300 transition-all bg-white dark:bg-[#2A2A2A] scroll-smooth min-h-screen flex flex-col justify-between`}>