added series home (#37)

This commit is contained in:
Kim, Jimin 2022-01-17 11:44:37 +09:00
parent 618c42d436
commit 21a48cc351
4 changed files with 117 additions and 25 deletions

View file

@ -3,6 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import {
faBook,
faCalendar,
faFile,
faHourglass,
} from "@fortawesome/free-solid-svg-icons"
@ -20,18 +21,28 @@ const StyledMetaContainer = styled.div`
const Meta = (props: { fetchedPage: PageData }) => {
return (
<StyledMetaContainer>
{/* posts count */}
<FontAwesomeIcon icon={faFile} />
&nbsp;&nbsp;
{props.fetchedPage.length
? props.fetchedPage.length + " posts"
: "no posts"}
&nbsp;&nbsp;&nbsp;&nbsp;
{/* date */}
<FontAwesomeIcon icon={faCalendar} />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;
{props.fetchedPage.date || "Unknown date"}
&nbsp;&nbsp;&nbsp;&nbsp;
{/* read time */}
<FontAwesomeIcon icon={faHourglass} />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;
{props.fetchedPage.readTime
? props.fetchedPage.readTime + " read"
: "unknown length"}
&nbsp;&nbsp;&nbsp;&nbsp;
{/* word count */}
<FontAwesomeIcon icon={faBook} />
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;
{props.fetchedPage.wordCount
? props.fetchedPage.wordCount + " words"
: "unknown words"}

View file

@ -2,14 +2,20 @@ import styled from "styled-components"
import { Link } from "react-router-dom"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
import { faArrowLeft, faArrowRight } from "@fortawesome/free-solid-svg-icons"
import {
faArrowLeft,
faArrowRight,
faListUl,
} from "@fortawesome/free-solid-svg-icons"
import theming from "../../styles/theming"
const StyledNextPrevContainer = styled.div`
const StyledContainer = styled.div`
display: flex;
justify-content: space-between;
size: 100%;
line-height: 1rem;
`
const StyledLink = styled(Link)`
@ -23,7 +29,6 @@ const StyledLink = styled(Link)`
height: 1rem;
width: 2rem;
margin-top: 2rem;
line-height: 1rem;
text-align: center;
@ -45,16 +50,19 @@ const StyledDisabledLink = styled.div`
height: 1rem;
width: 2rem;
margin-top: 2rem;
line-height: 1rem;
text-align: center;
user-select: none;
`
const NextPrevButtons = (props: { prevURL?: string; nextURL?: string }) => {
const SeriesControlButtons = (props: {
seriesHome: string
prevURL?: string
nextURL?: string
}) => {
return (
<StyledNextPrevContainer>
<StyledContainer>
{props.prevURL ? (
<StyledLink to={props.prevURL}>
<FontAwesomeIcon icon={faArrowLeft} />
@ -64,6 +72,11 @@ const NextPrevButtons = (props: { prevURL?: string; nextURL?: string }) => {
<FontAwesomeIcon icon={faArrowLeft} />
</StyledDisabledLink>
)}
<StyledLink to={props.seriesHome}>
<FontAwesomeIcon icon={faListUl} />
</StyledLink>
{props.nextURL ? (
<StyledLink to={props.nextURL}>
<FontAwesomeIcon icon={faArrowRight} />
@ -73,8 +86,8 @@ const NextPrevButtons = (props: { prevURL?: string; nextURL?: string }) => {
<FontAwesomeIcon icon={faArrowRight} />
</StyledDisabledLink>
)}
</StyledNextPrevContainer>
</StyledContainer>
)
}
export default NextPrevButtons
export default SeriesControlButtons

View file

@ -7,13 +7,14 @@ import { PageData, Map } from "../../../types/types"
import GithubLinkIcon from "../../components/GithubLinkIcon"
import MainContent from "../../components/MainContent"
import PostCard from "../../components/PostCard"
import Loading from "../../components/Loading"
import TagList from "../../components/TagList"
import Badge from "../../components/Badge"
import Tag from "../../components/Tag"
import NotFound from "../NotFound"
import NextPrevButtons from "./NextPrevButtons"
import SeriesControlButtons from "./SeriesControlButtons"
import Meta from "./Meta"
import Toc from "./Toc"
@ -47,6 +48,7 @@ const ProjectImage = styled.img`
enum PageType {
POST,
SERIES,
SERIES_HOME,
PORTFOLIO_PROJECT,
UNSEARCHABLE,
}
@ -65,7 +67,15 @@ const fetchContent = async (pageType: PageType, url: string) => {
const categorizePageType = (url: string): PageType => {
if (url.startsWith("/post")) return PageType.POST
if (url.startsWith("/series")) return PageType.SERIES
if (url.startsWith("/series")) {
if ([...(url.match(/\//g) || [])].length == 2) {
// url: /series/series-title
return PageType.SERIES_HOME
} else {
// url: /series/series-title/post-title
return PageType.SERIES
}
}
if (url.startsWith("/portfolio")) return PageType.PORTFOLIO_PROJECT
return PageType.UNSEARCHABLE
@ -80,22 +90,25 @@ const Page = () => {
useEffect(() => {
const url = location.pathname.replace(/\/$/, "") // remove trailing slash
const _pageType = categorizePageType(url)
const pageType = categorizePageType(url)
/**
* Test if url is a valid one
*/
let show404 = false
switch (_pageType) {
switch (pageType) {
case PageType.POST: {
if (!map.posts[url]) show404 = true
break
}
case PageType.SERIES_HOME:
case PageType.SERIES: {
if (!(url.slice(0, url.lastIndexOf("/")) in map.series)) show404 = true
show404 = !Object.keys(map.series).some((seriesHomeURL) =>
url.startsWith(seriesHomeURL)
)
break
}
@ -131,7 +144,18 @@ const Page = () => {
toc: undefined,
content: "No content",
// series
seriesHome: "",
prev: "",
next: "",
// series home
order: [],
length: 0,
// portfolio
image: "",
overview: "",
@ -139,13 +163,13 @@ const Page = () => {
repo: "",
}
fetchContent(_pageType, url).then((fetched_content) => {
fetchContent(pageType, url).then((fetched_content) => {
if (!fetched_content) {
setIsLoading(false)
return
}
switch (_pageType) {
switch (pageType) {
case PageType.POST: {
const post = map.posts[url]
@ -190,6 +214,21 @@ const Page = () => {
break
}
case PageType.SERIES_HOME: {
const seriesData = map.series[url]
pageData.title = seriesData.title
pageData.content = fetched_content.content
pageData.date = seriesData.date
pageData.readTime = seriesData.readTime
pageData.wordCount = seriesData.wordCount
pageData.order = seriesData.order
pageData.length = seriesData.length
break
}
case PageType.PORTFOLIO_PROJECT: {
const data =
portfolio.projects[url as keyof typeof portfolio.projects]
@ -214,7 +253,11 @@ const Page = () => {
}
}
setPageType(_pageType)
/**
* Apply result
*/
setPageType(pageType)
setPageData(pageData)
setIsLoading(false)
@ -241,7 +284,11 @@ const Page = () => {
<MainContent>
{/* next/previous series post buttons */}
{pageType == PageType.SERIES && (
<NextPrevButtons prevURL={pageData.prev} nextURL={pageData.next} />
<SeriesControlButtons
seriesHome={pageData.seriesHome}
prevURL={pageData.prev}
nextURL={pageData.next}
/>
)}
{pageType == PageType.PORTFOLIO_PROJECT && pageData.repo && (
@ -273,9 +320,9 @@ const Page = () => {
<br />
{/* Post metadata */}
{[PageType.POST, PageType.SERIES].includes(pageType) && (
<Meta fetchedPage={pageData} />
)}
{[PageType.POST, PageType.SERIES, PageType.SERIES_HOME].includes(
pageType
) && <Meta fetchedPage={pageData} />}
</small>
<hr />
@ -294,6 +341,21 @@ const Page = () => {
}}
/>
</MainContent>
{/* series post list */}
{pageType == PageType.SERIES_HOME &&
pageData.order.map((post) => {
return (
<PostCard
key={post}
postData={{
url: post,
...map.posts[post],
}}
/>
)
})}
</>
)
}

View file

@ -62,12 +62,18 @@ export interface PageData {
toc?: string
content: string
// series-specific data
// series
seriesHome: string
prev?: string
next?: string
// portfolio-specific data
// series home
order: string[]
length: number
// portfolio
image: string // image url
overview: string