Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Theme medium #41

Merged
merged 4 commits into from
Jan 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions components/CollapseLeft.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { useEffect, useRef } from 'react'

const Collapse = props => {
const collapseRef = useRef(null)
const collapseSection = element => {
const sectionWidth = element.scrollWidth
requestAnimationFrame(function () {
element.style.width = sectionWidth + 'px'
requestAnimationFrame(function () {
element.style.width = 0 + 'px'
})
})
}
const expandSection = element => {
const sectionWidth = element.scrollWidth
element.style.width = sectionWidth + 'px'
const clearTime = setTimeout(() => {
element.style.width = 'auto'
}, 400)
clearTimeout(clearTime)
}
useEffect(() => {
const element = collapseRef.current
if (props.isOpen) {
expandSection(element)
} else {
collapseSection(element)
}
}, [props.isOpen])
return (
<div ref={collapseRef} style={{ width: '0px' }} className={'overflow-hidden duration-200 ' + props.className}>
{props.children}
</div>
)
}
Collapse.defaultProps = { isOpen: false }

export default Collapse
55 changes: 55 additions & 0 deletions components/SideBarDrawer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { useRouter } from 'next/router'
import React from 'react'

/**
* 侧边栏抽屉面板,可以从侧面拉出
* @returns {JSX.Element}
* @constructor
*/
const SideBarDrawer = ({ children, isOpen, onOpen, onClose, className }) => {
const router = useRouter()
React.useEffect(() => {
// 页面渲染后删除hidden属性
// const sideBarWrapperElement = document.getElementById('sidebar-wrapper')
// sideBarWrapperElement?.classList?.remove('hidden')

const sideBarDrawerRouteListener = () => {
switchSideDrawerVisible(false)
}
router.events.on('routeChangeComplete', sideBarDrawerRouteListener)
return () => {
router.events.off('routeChangeComplete', sideBarDrawerRouteListener)
}
}, [router.events])

// 点击按钮更改侧边抽屉状态
const switchSideDrawerVisible = (showStatus) => {
if (window) {
if (showStatus) {
onOpen()
} else {
onClose()
}
const sideBarDrawer = window.document.getElementById('sidebar-drawer')
const sideBarDrawerBackground = window.document.getElementById('sidebar-drawer-background')

if (showStatus) {
sideBarDrawer.classList.replace('-ml-80', 'ml-0')
sideBarDrawerBackground.classList.replace('hidden', 'block')
} else {
sideBarDrawer.classList.replace('ml-0', '-ml-80')
sideBarDrawerBackground.classList.replace('block', 'hidden')
}
}
}

return <div id='sidebar-wrapper' className={' ' + className}>
<div id='sidebar-drawer' className={`${isOpen ? 'ml-0' : '-ml-80'} bg-white dark:bg-gray-900 flex flex-col duration-300 fixed h-full left-0 overflow-y-scroll scroll-hidden top-0 z-50`}>
{children}
</div>
{/* 背景蒙版 */}
<div id='sidebar-drawer-background' onClick={() => { switchSideDrawerVisible(false) }}
className={`${isOpen ? 'block' : 'hidden'} animate__animated animate__fadeIn fixed top-0 duration-300 left-0 z-30 w-full h-full glassmorphism`}/>
</div>
}
export default SideBarDrawer
6 changes: 6 additions & 0 deletions themes/Medium/Layout404.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

export const Layout404 = () => {
return <div>
404 Not found.
</div>
}
6 changes: 6 additions & 0 deletions themes/Medium/LayoutArchive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const LayoutArchive = (props) => {
// const { posts, tags, categories, postCount } = props
return <div {...props}>
Archive Page
</div>
}
33 changes: 33 additions & 0 deletions themes/Medium/LayoutBase.js
Original file line number Diff line number Diff line change
@@ -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, showInfoCard = true } = 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'>
{showInfoCard && <InfoCard/>}
</div>
<div className='lg:ml-72 max-w-3xl w-full px-5'>
{children}
</div>
</main>
<Footer/>
</div>
)
}

export default LayoutBase
8 changes: 8 additions & 0 deletions themes/Medium/LayoutCategory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import LayoutBase from './LayoutBase'

export const LayoutCategory = (props) => {
const { category } = props
return <LayoutBase {...props}>
Category - {category}
</LayoutBase>
}
8 changes: 8 additions & 0 deletions themes/Medium/LayoutCategoryIndex.js
Original file line number Diff line number Diff line change
@@ -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 changes: 9 additions & 0 deletions themes/Medium/LayoutIndex.js
Original file line number Diff line number Diff line change
@@ -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>
}
9 changes: 9 additions & 0 deletions themes/Medium/LayoutPage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import LayoutBase from './LayoutBase'
import BlogPostListPage from './components/BlogPostListPage'

export const LayoutPage = (props) => {
const { page, posts, postCount } = props
return <LayoutBase {...props}>
<BlogPostListPage page={page} posts={posts} postCount={postCount} />
</LayoutBase>
}
31 changes: 31 additions & 0 deletions themes/Medium/LayoutSearch.js
Original file line number Diff line number Diff line change
@@ -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
}
73 changes: 73 additions & 0 deletions themes/Medium/LayoutSlug.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
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'
import Image from 'next/image'
import { useGlobal } from '@/lib/global'
import formatDate from '@/lib/formatDate'
import Link from 'next/link'

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)
}
const { locale } = useGlobal()
const date = formatDate(post?.date?.start_date || post.createdTime, locale.LOCALE)

return <LayoutBase {...props} meta={meta} showInfoCard={false}>
<h1 className='text-4xl mt-12 font-sans'>{post?.title}</h1>
<Link href='/about' passHref>
<div className='flex py-3 items-center font-sans cursor-pointer'>
<Image
alt={BLOG.AUTHOR}
width={25}
height={25}
loading='lazy'
src='/avatar.jpg'
className='rounded-full'
/>
<div className='mr-3 ml-1 text-green-500'>{BLOG.AUTHOR}</div>
<div className='text-gray-500'>{date}</div>
</div>
</Link>
{/* 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 changes: 8 additions & 0 deletions themes/Medium/LayoutTag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import LayoutBase from './LayoutBase'

export const LayoutTag = (props) => {
const { tag } = props
return <LayoutBase>
Tag - {tag}
</LayoutBase>
}
8 changes: 8 additions & 0 deletions themes/Medium/LayoutTagIndex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import LayoutBase from './LayoutBase'

export const LayoutTagIndex = (props) => {
// const { tags, categories, postCount, latestPosts } = props
return <LayoutBase {...props}>
TagIndex
</LayoutBase>
}
66 changes: 66 additions & 0 deletions themes/Medium/components/BlogPostCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import BLOG from '@/blog.config'
import { useGlobal } from '@/lib/global'
import { faAngleRight } 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 CONFIG_MEDIUM from '../config_medium'

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>
<hr className='w-full'/>

</div>

)
}

const mapPageUrl = id => {
return 'https://www.notion.so/' + id.replace(/-/g, '')
}

export default BlogPostCard
12 changes: 12 additions & 0 deletions themes/Medium/components/BlogPostListEmpty.js
Original file line number Diff line number Diff line change
@@ -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
Loading