mirror of
https://github.com/d0zingcat/NotionNext.git
synced 2026-05-14 15:09:22 +00:00
feature: 提交medium主题初版
This commit is contained in:
6
themes/Medium/Layout404.js
Normal file
6
themes/Medium/Layout404.js
Normal file
@@ -0,0 +1,6 @@
|
||||
|
||||
export const Layout404 = () => {
|
||||
return <div>
|
||||
404 Not found.
|
||||
</div>
|
||||
}
|
||||
6
themes/Medium/LayoutArchive.js
Normal file
6
themes/Medium/LayoutArchive.js
Normal file
@@ -0,0 +1,6 @@
|
||||
export const LayoutArchive = (props) => {
|
||||
// const { posts, tags, categories, postCount } = props
|
||||
return <div {...props}>
|
||||
Archive Page
|
||||
</div>
|
||||
}
|
||||
33
themes/Medium/LayoutBase.js
Normal file
33
themes/Medium/LayoutBase.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import CommonHead from '@/components/CommonHead'
|
||||
import React from 'react'
|
||||
import Footer from './components/Footer'
|
||||
import InfoCard from './components/InfoCard'
|
||||
import LogoBar from './components/LogoBar'
|
||||
|
||||
/**
|
||||
* 基础布局 采用左右两侧布局,移动端使用顶部导航栏
|
||||
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const LayoutBase = props => {
|
||||
const { children, meta } = props
|
||||
|
||||
return (
|
||||
<div className='bg-white w-full h-full min-h-screen justify-center'>
|
||||
<CommonHead meta={meta}/>
|
||||
<main id="wrapper" className='max-w-7xl w-full h-full mx-auto'>
|
||||
<LogoBar/>
|
||||
<div className='pt-12 fixed top-24 w-80 pl-8 hidden lg:block'>
|
||||
<InfoCard/>
|
||||
</div>
|
||||
<div className='lg:ml-72 max-w-3xl w-full px-5'>
|
||||
{children}
|
||||
</div>
|
||||
</main>
|
||||
<Footer/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LayoutBase
|
||||
8
themes/Medium/LayoutCategory.js
Normal file
8
themes/Medium/LayoutCategory.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
export const LayoutCategory = (props) => {
|
||||
const { category } = props
|
||||
return <LayoutBase {...props}>
|
||||
Category - {category}
|
||||
</LayoutBase>
|
||||
}
|
||||
8
themes/Medium/LayoutCategoryIndex.js
Normal file
8
themes/Medium/LayoutCategoryIndex.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
export const LayoutCategoryIndex = (props) => {
|
||||
// const { tags, allPosts, categories, postCount, latestPosts } = props
|
||||
return <LayoutBase {...props}>
|
||||
CategoryIndex
|
||||
</LayoutBase>
|
||||
}
|
||||
9
themes/Medium/LayoutIndex.js
Normal file
9
themes/Medium/LayoutIndex.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import BlogPostListPage from './components/BlogPostListPage'
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
export const LayoutIndex = (props) => {
|
||||
// const { posts, tags, meta, categories, postCount, latestPosts } = props
|
||||
return <LayoutBase {...props}>
|
||||
<BlogPostListPage {...props}/>
|
||||
</LayoutBase>
|
||||
}
|
||||
8
themes/Medium/LayoutPage.js
Normal file
8
themes/Medium/LayoutPage.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import LayoutBase from '../Hexo/LayoutBase'
|
||||
|
||||
export const LayoutPage = (props) => {
|
||||
const { page } = props
|
||||
return <LayoutBase {...props}>
|
||||
Page - {page}
|
||||
</LayoutBase>
|
||||
}
|
||||
31
themes/Medium/LayoutSearch.js
Normal file
31
themes/Medium/LayoutSearch.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { useRouter } from 'next/router'
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
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)
|
||||
|
||||
return <LayoutBase {...props}>
|
||||
Search {searchKey}
|
||||
</LayoutBase>
|
||||
}
|
||||
|
||||
function getSearchKey () {
|
||||
const router = useRouter()
|
||||
if (router.query && router.query.s) {
|
||||
return router.query.s
|
||||
}
|
||||
return null
|
||||
}
|
||||
53
themes/Medium/LayoutSlug.js
Normal file
53
themes/Medium/LayoutSlug.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { getPageTableOfContents } from 'notion-utils'
|
||||
import 'prismjs'
|
||||
import 'prismjs/components/prism-bash'
|
||||
import 'prismjs/components/prism-javascript'
|
||||
import 'prismjs/components/prism-markup'
|
||||
import 'prismjs/components/prism-python'
|
||||
import 'prismjs/components/prism-typescript'
|
||||
import { Code, Collection, CollectionRow, Equation, NotionRenderer } from 'react-notion-x'
|
||||
import LayoutBase from './LayoutBase'
|
||||
import Comment from '@/components/Comment'
|
||||
|
||||
const mapPageUrl = id => {
|
||||
return 'https://www.notion.so/' + id.replace(/-/g, '')
|
||||
}
|
||||
|
||||
export const LayoutSlug = (props) => {
|
||||
const { post } = props
|
||||
const meta = {
|
||||
title: `${post.title} | ${BLOG.TITLE}`,
|
||||
description: post.summary,
|
||||
type: 'article',
|
||||
tags: post.tags
|
||||
}
|
||||
|
||||
if (post?.blockMap?.block) {
|
||||
post.content = Object.keys(post.blockMap.block)
|
||||
post.toc = getPageTableOfContents(post, post.blockMap)
|
||||
}
|
||||
|
||||
return <LayoutBase {...props} meta={meta}>
|
||||
<h1 className='text-4xl mt-12'>{post?.title}</h1>
|
||||
{/* Notion文章主体 */}
|
||||
<section id='notion-article' className='px-1 max-w-5xl'>
|
||||
{post.blockMap && (
|
||||
<NotionRenderer
|
||||
recordMap={post.blockMap}
|
||||
mapPageUrl={mapPageUrl}
|
||||
components={{
|
||||
equation: Equation,
|
||||
code: Code,
|
||||
collectionRow: CollectionRow,
|
||||
collection: Collection
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
<div>
|
||||
<Comment frontMatter={post}/>
|
||||
|
||||
</div>
|
||||
</LayoutBase>
|
||||
}
|
||||
8
themes/Medium/LayoutTag.js
Normal file
8
themes/Medium/LayoutTag.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
export const LayoutTag = (props) => {
|
||||
const { tag } = props
|
||||
return <LayoutBase>
|
||||
Tag - {tag}
|
||||
</LayoutBase>
|
||||
}
|
||||
8
themes/Medium/LayoutTagIndex.js
Normal file
8
themes/Medium/LayoutTagIndex.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import LayoutBase from './LayoutBase'
|
||||
|
||||
export const LayoutTagIndex = (props) => {
|
||||
// const { tags, categories, postCount, latestPosts } = props
|
||||
return <LayoutBase {...props}>
|
||||
TagIndex
|
||||
</LayoutBase>
|
||||
}
|
||||
80
themes/Medium/components/BlogPostCard.js
Normal file
80
themes/Medium/components/BlogPostCard.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { faAngleRight, faFolder } from '@fortawesome/free-solid-svg-icons'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
import { Code, Collection, CollectionRow, Equation, NotionRenderer } from 'react-notion-x'
|
||||
import TagItemMini from './TagItemMini'
|
||||
import CONFIG_MEDIUM from '../config_medium'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
|
||||
const BlogPostCard = ({ post, showSummary }) => {
|
||||
const showPreview = CONFIG_MEDIUM.POST_LIST_PREVIEW && post.blockMap
|
||||
const { locale } = useGlobal()
|
||||
return (
|
||||
<div key={post.id} className='animate__animated animate__fadeIn duration-300 mb-6 max-w-7xl '>
|
||||
|
||||
<div className='lg:p-8 p-4 flex flex-col w-full'>
|
||||
<Link href={`${BLOG.PATH}/article/${post.slug}`} passHref>
|
||||
<a className={'cursor-pointer font-bold font-sans hover:underline text-4xl flex justify-start leading-tight text-gray-700 dark:text-gray-100 hover:text-blue-500 dark:hover:text-blue-400'}>
|
||||
{post.title}
|
||||
</a>
|
||||
</Link>
|
||||
|
||||
<div className={'flex mt-2 items-center justify-start flex-wrap dark:text-gray-500 text-gray-400 hover:text-blue-500 dark:hover:text-blue-400 '}>
|
||||
{post.date.start_date}
|
||||
</div>
|
||||
|
||||
{(!showPreview || showSummary) && <p className='my-4 text-gray-700 dark:text-gray-300 text-sm font-light leading-7'>
|
||||
{post.summary}
|
||||
</p>}
|
||||
|
||||
{showPreview && <div className='overflow-ellipsis truncate'>
|
||||
<NotionRenderer
|
||||
bodyClassName='max-h-full'
|
||||
recordMap={post.blockMap}
|
||||
mapPageUrl={mapPageUrl}
|
||||
components={{
|
||||
equation: Equation,
|
||||
code: Code,
|
||||
collectionRow: CollectionRow,
|
||||
collection: Collection
|
||||
}}
|
||||
/>
|
||||
<div className='article-cover pointer-events-none'>
|
||||
<div className='w-full justify-start flex'>
|
||||
<Link href={`${BLOG.PATH}/article/${post.slug}`} passHref>
|
||||
<a className='hover:bg-opacity-100 hover:scale-105 duration-200 pointer-events-auto transform text-red-500 cursor-pointer'>
|
||||
{locale.COMMON.ARTICLE_DETAIL}
|
||||
<FontAwesomeIcon className='ml-1' icon={faAngleRight} /></a>
|
||||
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div> }
|
||||
|
||||
{/* <div className='text-gray-400 justify-between flex'>
|
||||
|
||||
<Link href={`/category/${post.category}`} passHref>
|
||||
<a className='cursor-pointer font-light text-sm hover:underline transform'>
|
||||
<FontAwesomeIcon icon={faFolder} className='mr-1' />{post.category}
|
||||
</a>
|
||||
</Link>
|
||||
<div className='md:flex-nowrap flex-wrap md:justify-start inline-block'>
|
||||
<div> {post.tagItems.map(tag => (<TagItemMini key={tag.name} tag={tag} />))}</div>
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
</div>
|
||||
<hr className='w-full'/>
|
||||
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
const mapPageUrl = id => {
|
||||
return 'https://www.notion.so/' + id.replace(/-/g, '')
|
||||
}
|
||||
|
||||
export default BlogPostCard
|
||||
12
themes/Medium/components/BlogPostListEmpty.js
Normal file
12
themes/Medium/components/BlogPostListEmpty.js
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
/**
|
||||
* 空白博客 列表
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListEmpty = ({ currentSearch }) => {
|
||||
return <div className='flex w-full items-center justify-center min-h-screen mx-auto md:-mt-20'>
|
||||
<p className='text-gray-500 dark:text-gray-300'>没有找到文章 {(currentSearch && <div>{currentSearch}</div>)}</p>
|
||||
</div>
|
||||
}
|
||||
export default BlogPostListEmpty
|
||||
32
themes/Medium/components/BlogPostListPage.js
Normal file
32
themes/Medium/components/BlogPostListPage.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import BlogPostCard from './BlogPostCard'
|
||||
import BLOG from '@/blog.config'
|
||||
import BlogPostListEmpty from './BlogPostListEmpty'
|
||||
import PaginationSimple from './PaginationSimple'
|
||||
|
||||
/**
|
||||
* 文章列表分页表格
|
||||
* @param page 当前页
|
||||
* @param posts 所有文章
|
||||
* @param tags 所有标签
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const BlogPostListPage = ({ page = 1, posts = [], postCount }) => {
|
||||
const totalPage = Math.ceil(postCount / BLOG.POSTS_PER_PAGE)
|
||||
|
||||
if (!posts || posts.length === 0) {
|
||||
return <BlogPostListEmpty />
|
||||
} else {
|
||||
return (
|
||||
<div id="container" className='w-full justify-center'>
|
||||
{/* 文章列表 */}
|
||||
{posts.map(post => (
|
||||
<BlogPostCard key={post.id} post={post} />
|
||||
))}
|
||||
<PaginationSimple page={page} totalPage={totalPage} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default BlogPostListPage
|
||||
9
themes/Medium/components/Card.js
Normal file
9
themes/Medium/components/Card.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const Card = ({ children, headerSlot, className }) => {
|
||||
return <div className={className}>
|
||||
<>{headerSlot}</>
|
||||
<section className="shadow px-2 py-4 bg-white dark:bg-gray-800 hover:shadow-xl duration-200">
|
||||
{children}
|
||||
</section>
|
||||
</div>
|
||||
}
|
||||
export default Card
|
||||
30
themes/Medium/components/Footer.js
Normal file
30
themes/Medium/components/Footer.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import { faCopyright, faEye, faShieldAlt, faUsers, faHeart } from '@fortawesome/free-solid-svg-icons'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import React from 'react'
|
||||
import BLOG from '@/blog.config'
|
||||
|
||||
const Footer = ({ title }) => {
|
||||
const d = new Date()
|
||||
const currentYear = d.getFullYear()
|
||||
const startYear = BLOG.SINCE && BLOG.SINCE !== currentYear && BLOG.SINCE + '-'
|
||||
return (
|
||||
<footer
|
||||
className='dark:bg-gray-900 flex-shrink-0 justify-center text-center m-auto w-full leading-6 text-gray-400 text-sm p-6'
|
||||
>
|
||||
<FontAwesomeIcon icon={faCopyright} /> {`${startYear}${currentYear}`} <span><FontAwesomeIcon icon={faHeart} className='mx-1 animate-pulse'/> <a href={BLOG.LINK} className='underline font-bold text-gray-500 dark:text-gray-300 '>{BLOG.AUTHOR}</a>.
|
||||
<br/>
|
||||
|
||||
<span>Powered by <a href='https://notion.so' className='underline font-bold text-gray-500 dark:text-gray-300'>Notion</a> & <a href='https://github.com/tangly1024/NotionNext' className='underline font-bold text-gray-500 dark:text-gray-300'>NotionNext</a>.</span></span>
|
||||
|
||||
{BLOG.BEI_AN && <><br /><FontAwesomeIcon icon={faShieldAlt} /> <a href='https://beian.miit.gov.cn/' className='mr-2'>{BLOG.BEI_AN}</a><br/></>}
|
||||
<span className='hidden busuanzi_container_site_pv'>
|
||||
<FontAwesomeIcon icon={faEye}/><span className='px-1 busuanzi_value_site_pv'> </span> </span>
|
||||
<span className='pl-2 hidden busuanzi_container_site_uv'>
|
||||
<FontAwesomeIcon icon={faUsers}/> <span className='px-1 busuanzi_value_site_uv'> </span> </span>
|
||||
<br/>
|
||||
<h1>{title}</h1>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
|
||||
export default Footer
|
||||
27
themes/Medium/components/InfoCard.js
Normal file
27
themes/Medium/components/InfoCard.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import Image from 'next/image'
|
||||
import Router from 'next/router'
|
||||
import React from 'react'
|
||||
import SocialButton from './SocialButton'
|
||||
|
||||
const InfoCard = () => {
|
||||
return <>
|
||||
<div className='items-center justify-start font-sans '>
|
||||
<div className='hover:scale-105 transform duration-200 cursor-pointer' onClick={ () => { Router.push('/about') }}>
|
||||
<Image
|
||||
alt={BLOG.AUTHOR}
|
||||
width={120}
|
||||
height={120}
|
||||
loading='lazy'
|
||||
src='/avatar.jpg'
|
||||
className='rounded-full'
|
||||
/>
|
||||
</div>
|
||||
<div className='text-xl py-2 hover:scale-105 transform duration-200'>{BLOG.AUTHOR}</div>
|
||||
<div className='font-light text-gray-600 mb-2 hover:scale-105 transform duration-200'>{BLOG.BIO}</div>
|
||||
<SocialButton/>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default InfoCard
|
||||
25
themes/Medium/components/LogoBar.js
Normal file
25
themes/Medium/components/LogoBar.js
Normal file
@@ -0,0 +1,25 @@
|
||||
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()
|
||||
|
||||
return <div id='top-wrapper' className='w-full flex justify-center font-sans'>
|
||||
<div className='flex mx-auto w-full items-center space-x-3 py-6 px-5'>
|
||||
<Link href='/'>
|
||||
<a className='text-3xl'>{BLOG.TITLE}</a>
|
||||
</Link>
|
||||
<Link href='/about'>
|
||||
<a className='text-gray-600'>{locale.NAV.ABOUT}</a>
|
||||
</Link>
|
||||
{BLOG.CONTACT_EMAIL && <Link href={`mailto:${BLOG.CONTACT_EMAIL}`} passHref>
|
||||
<div className='bg-black px-2 py-1 rounded-full'>
|
||||
<FontAwesomeIcon className='cursor-pointer text-white' icon={faEnvelope}/>
|
||||
</div>
|
||||
</Link>}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
42
themes/Medium/components/PaginationSimple.js
Normal file
42
themes/Medium/components/PaginationSimple.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import Link from 'next/link'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useGlobal } from '@/lib/global'
|
||||
|
||||
/**
|
||||
* 简易翻页插件
|
||||
* @param page 当前页码
|
||||
* @param showNext 是否有下一页
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const PaginationSimple = ({ page, showNext }) => {
|
||||
const { locale } = useGlobal()
|
||||
const router = useRouter()
|
||||
const currentPage = +page
|
||||
return (
|
||||
<div className='my-10 flex justify-between font-medium text-black dark:text-gray-100 space-x-2'>
|
||||
<Link
|
||||
href={ {
|
||||
pathname: (currentPage === 2 ? `${BLOG.PATH || '/'}` : `/page/${currentPage - 1}`), query: router.query.s ? { s: router.query.s } : {}
|
||||
} } passHref >
|
||||
<a
|
||||
rel='prev'
|
||||
className={`${currentPage === 1 ? 'invisible' : 'block'} text-center w-full duration-200 px-4 py-2 hover:border-black border-b-2 hover:font-bold`}
|
||||
>
|
||||
← {locale.PAGINATION.PREV}
|
||||
</a>
|
||||
</Link>
|
||||
<Link href={ { pathname: `/page/${currentPage + 1}`, query: router.query.s ? { s: router.query.s } : {} } } passHref>
|
||||
<a
|
||||
rel='next'
|
||||
className={`${+showNext ? 'block' : 'invisible'} text-center w-full duration-200 px-4 py-2 hover:border-black border-b-2 hover:font-bold`}
|
||||
>
|
||||
{locale.PAGINATION.NEXT} →
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PaginationSimple
|
||||
36
themes/Medium/components/SocialButton.js
Normal file
36
themes/Medium/components/SocialButton.js
Normal file
@@ -0,0 +1,36 @@
|
||||
import BLOG from '@/blog.config'
|
||||
import { faGithub, faTelegram, faTwitter, faWeibo } from '@fortawesome/free-brands-svg-icons'
|
||||
import { faEnvelope, faRss } from '@fortawesome/free-solid-svg-icons'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import React from 'react'
|
||||
|
||||
/**
|
||||
* 社交联系方式按钮组
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const SocialButton = () => {
|
||||
return <div className='w-52 flex-wrap flex'>
|
||||
<div className='space-x-3 text-xl text-gray-600 dark:text-gray-400 '>
|
||||
{BLOG.CONTACT_GITHUB && <a target='_blank' rel='noreferrer' title={'github'} href={BLOG.CONTACT_GITHUB} >
|
||||
<FontAwesomeIcon icon={faGithub} className='transform hover:scale-125 duration-150'/>
|
||||
</a>}
|
||||
{BLOG.CONTACT_TWITTER && <a target='_blank' rel='noreferrer' title={'twitter'} href={BLOG.CONTACT_TWITTER} >
|
||||
<FontAwesomeIcon icon={faTwitter} className='transform hover:scale-125 duration-150'/>
|
||||
</a>}
|
||||
{BLOG.CONTACT_TELEGRAM && <a target='_blank' rel='noreferrer' href={BLOG.CONTACT_TELEGRAM} title={'telegram'} >
|
||||
<FontAwesomeIcon icon={faTelegram} className='transform hover:scale-125 duration-150'/>
|
||||
</a>}
|
||||
{BLOG.CONTACT_WEIBO && <a target='_blank' rel='noreferrer' title={'weibo'} href={BLOG.CONTACT_WEIBO} >
|
||||
<FontAwesomeIcon icon={faWeibo} className='transform hover:scale-125 duration-150'/>
|
||||
</a>}
|
||||
{BLOG.CONTACT_EMAIL && <a target='_blank' rel='noreferrer' title={'email'} href={`mailto:${BLOG.CONTACT_EMAIL}`} >
|
||||
<FontAwesomeIcon icon={faEnvelope} className='transform hover:scale-125 duration-150'/>
|
||||
</a>}
|
||||
<a target='_blank' rel='noreferrer' title={'RSS'} href={'/feed'} >
|
||||
<FontAwesomeIcon icon={faRss} className='transform hover:scale-125 duration-150'/>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
export default SocialButton
|
||||
17
themes/Medium/components/TagItemMini.js
Normal file
17
themes/Medium/components/TagItemMini.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { faTag } from '@fortawesome/free-solid-svg-icons'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import Link from 'next/link'
|
||||
|
||||
const TagItemMini = ({ tag, selected = false }) => {
|
||||
return <Link key={tag} href={selected ? '/' : `/tag/${encodeURIComponent(tag.name)}`} passHref>
|
||||
<a className={`cursor-pointer inline-block rounded hover:bg-gray-500 hover:text-white duration-200
|
||||
mr-2 py-0.5 px-1 text-xs whitespace-nowrap dark:hover:text-white
|
||||
${selected
|
||||
? 'text-white dark:text-gray-300 bg-black dark:bg-black dark:hover:bg-gray-900'
|
||||
: `text-gray-600 hover:shadow-xl dark:border-gray-400 notion-${tag.color}_background dark:bg-gray-800`}` }>
|
||||
<div className='font-light dark:text-gray-400'>{selected && <FontAwesomeIcon icon={faTag} className='mr-1'/>} {tag.name + (tag.count ? `(${tag.count})` : '')} </div>
|
||||
</a>
|
||||
</Link>
|
||||
}
|
||||
|
||||
export default TagItemMini
|
||||
13
themes/Medium/config_medium.js
Normal file
13
themes/Medium/config_medium.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const CONFIG_MEDIUM = {
|
||||
|
||||
POST_LIST_COVER: true, // 文章列表显示图片封面
|
||||
POST_LIST_PREVIEW: true, // 显示文章预览
|
||||
|
||||
// 菜单
|
||||
MENU_ABOUT: true, // 显示关于
|
||||
MENU_CATEGORY: true, // 显示分类
|
||||
MENU_TAG: true, // 显示标签
|
||||
MENU_ARCHIVE: true, // 显示归档
|
||||
MENU_SEARCH: true // 显示搜索
|
||||
}
|
||||
export default CONFIG_MEDIUM
|
||||
12
themes/Medium/index.js
Normal file
12
themes/Medium/index.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import CONFIG_MEDIUM from './config_medium'
|
||||
export { CONFIG_MEDIUM as THEME_CONFIG }
|
||||
export { LayoutIndex } from './LayoutIndex'
|
||||
export { LayoutSearch } from './LayoutSearch'
|
||||
export { LayoutArchive } from './LayoutArchive'
|
||||
export { LayoutSlug } from './LayoutSlug'
|
||||
export { Layout404 } from './Layout404'
|
||||
export { LayoutCategory } from './LayoutCategory'
|
||||
export { LayoutCategoryIndex } from './LayoutCategoryIndex'
|
||||
export { LayoutPage } from './LayoutPage'
|
||||
export { LayoutTag } from './LayoutTag'
|
||||
export { LayoutTagIndex } from './LayoutTagIndex'
|
||||
@@ -5,4 +5,5 @@
|
||||
// export * from './Empty' // 空主题
|
||||
// export * from './NEXT'
|
||||
// export * from './Fukasawa'
|
||||
export * from './Hexo'
|
||||
// export * from './Hexo'
|
||||
export * from './Medium'
|
||||
|
||||
Reference in New Issue
Block a user