diff --git a/components/Tabs.js b/components/Tabs.js index 66012477..6f7497ba 100644 --- a/components/Tabs.js +++ b/components/Tabs.js @@ -5,7 +5,7 @@ import React, { useState } from 'react' * @param {*} param0 * @returns */ -const Tabs = ({ children }) => { +const Tabs = ({ className, children }) => { if (!children) { return <> } @@ -18,7 +18,7 @@ const Tabs = ({ children }) => { }) if (count === 1) { - return
+ return
{children}
} @@ -29,7 +29,7 @@ const Tabs = ({ children }) => { setCurrentTab(i) } - return
+ return
    {children.map((item, index) => { return
  • { const { children, meta, showInfoCard = true, slotRight } = props return ( -
    - -
    - -
    - {showInfoCard && } +
    + +
    + + {/* 桌面端左侧菜单 */} +
    +
    + +
    + +
    + +
    -
    + +
    + {/* 移动端顶部菜单 */} + +
    {children} +
    -
    - { CONFIG_MEDIUM.WIDGET_REVOLVER_MAPS === 'true' && } - { slotRight } + + {/* 桌面端右侧 */} +
    + + {slotRight &&
    {slotRight}
    } +
    + + {showInfoCard && } + {CONFIG_MEDIUM.WIDGET_REVOLVER_MAPS === 'true' && } +
    +
    + + {/* 移动端底部 */} +
    ) diff --git a/themes/Medium/LayoutIndex.js b/themes/Medium/LayoutIndex.js index 3d336bd7..884b825a 100644 --- a/themes/Medium/LayoutIndex.js +++ b/themes/Medium/LayoutIndex.js @@ -2,7 +2,6 @@ import BlogPostListPage from './components/BlogPostListPage' import LayoutBase from './LayoutBase' export const LayoutIndex = (props) => { - // const { posts, tags, meta, categories, postCount, latestPosts } = props return diff --git a/themes/Medium/LayoutPage.js b/themes/Medium/LayoutPage.js index 0c6640c8..cec493ce 100644 --- a/themes/Medium/LayoutPage.js +++ b/themes/Medium/LayoutPage.js @@ -2,8 +2,7 @@ import LayoutBase from './LayoutBase' import BlogPostListPage from './components/BlogPostListPage' export const LayoutPage = (props) => { - const { page, posts, postCount } = props return - + } diff --git a/themes/Medium/LayoutSearch.js b/themes/Medium/LayoutSearch.js index c7469a60..cd66e5e8 100644 --- a/themes/Medium/LayoutSearch.js +++ b/themes/Medium/LayoutSearch.js @@ -1,31 +1,24 @@ -import { useRouter } from 'next/router' import LayoutBase from './LayoutBase' +import BlogPostListPage from './components/BlogPostListPage' +import SearchInput from './components/SearchInput' +import { useGlobal } from '@/lib/global' +import TagGroups from './components/TagGroups' +import CategoryGroup from './components/CategoryGroup' export const LayoutSearch = (props) => { - const { posts } = props - let filteredPosts - const searchKey = getSearchKey() - if (searchKey) { - filteredPosts = posts.filter(post => { - const tagContent = post.tags ? post.tags.join(' ') : '' - const searchContent = post.title + post.summary + tagContent - return searchContent.toLowerCase().includes(searchKey.toLowerCase()) - }) - } else { - filteredPosts = posts - } - - console.log(filteredPosts) - + const { locale } = useGlobal() return - Search {searchKey} + +
    +
    + {locale.NAV.SEARCH} +
    + + + + +
    + +
    } - -function getSearchKey () { - const router = useRouter() - if (router.query && router.query.s) { - return router.query.s - } - return null -} diff --git a/themes/Medium/LayoutSlug.js b/themes/Medium/LayoutSlug.js index 905d8ed8..14419392 100644 --- a/themes/Medium/LayoutSlug.js +++ b/themes/Medium/LayoutSlug.js @@ -56,22 +56,24 @@ export const LayoutSlug = (props) => { } }) - return }> -

    {post?.title}

    - -
    - {BLOG.AUTHOR} -
    {BLOG.AUTHOR}
    -
    {date}
    -
    - + return }> +

    {post?.title}

    +
    + + <> + {BLOG.AUTHOR} +
    {BLOG.AUTHOR}
    + + +
    {date}
    +
    {/* Notion文章主体 */}
    {post.blockMap && ( diff --git a/themes/Medium/components/BlogPostListPage.js b/themes/Medium/components/BlogPostListPage.js index fe91b9b0..0c6b56b8 100644 --- a/themes/Medium/components/BlogPostListPage.js +++ b/themes/Medium/components/BlogPostListPage.js @@ -2,6 +2,7 @@ import BlogPostCard from './BlogPostCard' import BLOG from '@/blog.config' import BlogPostListEmpty from './BlogPostListEmpty' import PaginationSimple from './PaginationSimple' +import { useRouter } from 'next/router' /** * 文章列表分页表格 @@ -12,7 +13,17 @@ import PaginationSimple from './PaginationSimple' * @constructor */ const BlogPostListPage = ({ page = 1, posts = [], postCount }) => { - const totalPage = Math.ceil(postCount / BLOG.POSTS_PER_PAGE) + let filteredPosts = Object.assign(posts) + const searchKey = getSearchKey() + if (searchKey) { + filteredPosts = posts.filter(post => { + const tagContent = post.tags ? post.tags.join(' ') : '' + const searchContent = post.title + post.summary + tagContent + return searchContent.toLowerCase().includes(searchKey.toLowerCase()) + }) + } + const filteredPostsCount = filteredPosts.length + const totalPage = Math.ceil(filteredPostsCount / BLOG.POSTS_PER_PAGE) if (!posts || posts.length === 0) { return @@ -20,7 +31,7 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount }) => { return (
    {/* 文章列表 */} - {posts.map(post => ( + {filteredPosts.map(post => ( ))} @@ -29,4 +40,12 @@ const BlogPostListPage = ({ page = 1, posts = [], postCount }) => { } } +function getSearchKey () { + const router = useRouter() + if (router.query && router.query.s) { + return router.query.s + } + return null +} + export default BlogPostListPage diff --git a/themes/Medium/components/BottomMenuBar.js b/themes/Medium/components/BottomMenuBar.js new file mode 100644 index 00000000..75c2a9e0 --- /dev/null +++ b/themes/Medium/components/BottomMenuBar.js @@ -0,0 +1,23 @@ +import { faHome, faSearch } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import Link from 'next/link' +import React from 'react' + +export default function BottomMenuBar ({ className }) { + return ( +
    +
    + +
    + +
    + + +
    + +
    + +
    +
    + ) +} diff --git a/themes/Medium/components/CategoryGroup.js b/themes/Medium/components/CategoryGroup.js new file mode 100644 index 00000000..6a1d040b --- /dev/null +++ b/themes/Medium/components/CategoryGroup.js @@ -0,0 +1,30 @@ +import { faFolder, faFolderOpen, faTag, faTh } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import Link from 'next/link' +import React from 'react' + +const CategoryGroup = ({ currentCategory, categories }) => { + if (!categories) { + return <> + } + return
    +
    分类
    +
    + {Object.keys(categories).map(category => { + const selected = currentCategory === category + return + +
    {category}({categories[category]}) +
    +
    + + })} +
    +
    +} + +export default CategoryGroup diff --git a/themes/Medium/components/InfoCard.js b/themes/Medium/components/InfoCard.js index 47d300f6..65e1e3ba 100644 --- a/themes/Medium/components/InfoCard.js +++ b/themes/Medium/components/InfoCard.js @@ -5,9 +5,9 @@ import React from 'react' import SocialButton from './SocialButton' const InfoCard = () => { - return <> -
    -
    { Router.push('/about') }}> + return
    +
    +
    { Router.push('/about') }}> {BLOG.AUTHOR} { className='rounded-full' />
    -
    {BLOG.AUTHOR}
    -
    {BLOG.BIO}
    +
    {BLOG.AUTHOR}
    +
    {BLOG.BIO}
    - +
    } export default InfoCard diff --git a/themes/Medium/components/LogoBar.js b/themes/Medium/components/LogoBar.js index 75a23aec..f8836744 100644 --- a/themes/Medium/components/LogoBar.js +++ b/themes/Medium/components/LogoBar.js @@ -1,25 +1,26 @@ import BLOG from '@/blog.config' -import { useGlobal } from '@/lib/global' import { faEnvelope } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import Link from 'next/link' export default function LogoBar () { - const { locale } = useGlobal() + // const { locale } = useGlobal() return
    -
    - - {BLOG.TITLE} - - - {locale.NAV.ABOUT} - - {BLOG.CONTACT_EMAIL && -
    - -
    - } +
    +
    + + {BLOG.TITLE} + + {/* */} + {/* {locale.NAV.ABOUT} */} + {/* */} +
    + {BLOG.CONTACT_EMAIL && +
    +
    + }
    +
    } diff --git a/themes/Medium/components/RevolverMaps.js b/themes/Medium/components/RevolverMaps.js index 57d2cccc..d839d85d 100644 --- a/themes/Medium/components/RevolverMaps.js +++ b/themes/Medium/components/RevolverMaps.js @@ -8,7 +8,7 @@ export default function RevolverMaps () { changeLoad(true) } }) - return
    + return
    } function initRevolverMaps () { diff --git a/themes/Medium/components/SearchInput.js b/themes/Medium/components/SearchInput.js new file mode 100644 index 00000000..53dc6637 --- /dev/null +++ b/themes/Medium/components/SearchInput.js @@ -0,0 +1,77 @@ +import { useRouter } from 'next/router' +import { useImperativeHandle, useRef, useState } from 'react' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faSearch, faSpinner, faTimes } from '@fortawesome/free-solid-svg-icons' + +const SearchInput = ({ currentTag, currentSearch, cRef, className }) => { + const [searchKey, setSearchKey] = useState(currentSearch || getSearchKey() || '') + const [onLoading, setLoadingState] = useState(false) + const router = useRouter() + const searchInputRef = useRef() + useImperativeHandle(cRef, () => { + return { + focus: () => { + searchInputRef?.current?.focus() + } + } + }) + + const handleSearch = (key) => { + if (key && key !== '') { + setLoadingState(true) + router.push({ pathname: '/search', query: { s: key } }).then(r => { + setLoadingState(false) + }) + } else { + router.push({ pathname: '/' }).then(r => { + }) + } + } + const handleKeyUp = (e) => { + if (e.keyCode === 13) { // 回车 + handleSearch(searchInputRef.current.value) + } else if (e.keyCode === 27) { // ESC + cleanSearch() + } + } + const cleanSearch = () => { + searchInputRef.current.value = '' + setSearchKey('') + } + + const updateSearchKey = (val) => { + setSearchKey(val) + } + + return
    + updateSearchKey(e.target.value)} + defaultValue={searchKey} + /> + +
    { handleSearch(searchKey) }}> + +
    + + {(searchKey && searchKey.length && +
    + +
    + )} +
    +} + +function getSearchKey () { + const router = useRouter() + if (router.query && router.query.s) { + return router.query.s + } + return null +} + +export default SearchInput diff --git a/themes/Medium/components/SocialButton.js b/themes/Medium/components/SocialButton.js index c50f5984..71f43da2 100644 --- a/themes/Medium/components/SocialButton.js +++ b/themes/Medium/components/SocialButton.js @@ -10,7 +10,7 @@ import React from 'react' * @constructor */ const SocialButton = () => { - return
    + return
    {BLOG.CONTACT_GITHUB && diff --git a/themes/Medium/components/TagGroups.js b/themes/Medium/components/TagGroups.js new file mode 100644 index 00000000..17da94b4 --- /dev/null +++ b/themes/Medium/components/TagGroups.js @@ -0,0 +1,29 @@ +import { faTag } from '@fortawesome/free-solid-svg-icons' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import TagItemMini from './TagItemMini' + +/** + * 标签组 + * @param tags + * @param currentTag + * @returns {JSX.Element} + * @constructor + */ +const TagGroups = ({ tags, currentTag }) => { + if (!tags) return <> + return ( +
    +
    标签
    +
    + { + tags.map(tag => { + const selected = tag.name === currentTag + return + }) + } +
    +
    + ) +} + +export default TagGroups diff --git a/themes/Medium/components/TagItemMini.js b/themes/Medium/components/TagItemMini.js index 9fec9e35..fb7e3013 100644 --- a/themes/Medium/components/TagItemMini.js +++ b/themes/Medium/components/TagItemMini.js @@ -5,7 +5,7 @@ import Link from 'next/link' const TagItemMini = ({ tag, selected = false }) => { return
    diff --git a/themes/Medium/components/TopNavBar.js b/themes/Medium/components/TopNavBar.js new file mode 100644 index 00000000..c73223c3 --- /dev/null +++ b/themes/Medium/components/TopNavBar.js @@ -0,0 +1,9 @@ +import LogoBar from '@/themes/Medium/components/LogoBar' + +export default function TopNavBar ({ className }) { + return
    +
    + +
    +
    +}