added series home (#37)
This commit is contained in:
parent
618c42d436
commit
21a48cc351
4 changed files with 117 additions and 25 deletions
|
@ -3,6 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||||
import {
|
import {
|
||||||
faBook,
|
faBook,
|
||||||
faCalendar,
|
faCalendar,
|
||||||
|
faFile,
|
||||||
faHourglass,
|
faHourglass,
|
||||||
} from "@fortawesome/free-solid-svg-icons"
|
} from "@fortawesome/free-solid-svg-icons"
|
||||||
|
|
||||||
|
@ -20,18 +21,28 @@ const StyledMetaContainer = styled.div`
|
||||||
const Meta = (props: { fetchedPage: PageData }) => {
|
const Meta = (props: { fetchedPage: PageData }) => {
|
||||||
return (
|
return (
|
||||||
<StyledMetaContainer>
|
<StyledMetaContainer>
|
||||||
|
{/* posts count */}
|
||||||
|
<FontAwesomeIcon icon={faFile} />
|
||||||
|
|
||||||
|
{props.fetchedPage.length
|
||||||
|
? props.fetchedPage.length + " posts"
|
||||||
|
: "no posts"}
|
||||||
|
|
||||||
|
{/* date */}
|
||||||
<FontAwesomeIcon icon={faCalendar} />
|
<FontAwesomeIcon icon={faCalendar} />
|
||||||
|
|
||||||
{props.fetchedPage.date || "Unknown date"}
|
{props.fetchedPage.date || "Unknown date"}
|
||||||
|
|
||||||
|
{/* read time */}
|
||||||
<FontAwesomeIcon icon={faHourglass} />
|
<FontAwesomeIcon icon={faHourglass} />
|
||||||
|
|
||||||
{props.fetchedPage.readTime
|
{props.fetchedPage.readTime
|
||||||
? props.fetchedPage.readTime + " read"
|
? props.fetchedPage.readTime + " read"
|
||||||
: "unknown length"}
|
: "unknown length"}
|
||||||
|
|
||||||
|
{/* word count */}
|
||||||
<FontAwesomeIcon icon={faBook} />
|
<FontAwesomeIcon icon={faBook} />
|
||||||
|
|
||||||
{props.fetchedPage.wordCount
|
{props.fetchedPage.wordCount
|
||||||
? props.fetchedPage.wordCount + " words"
|
? props.fetchedPage.wordCount + " words"
|
||||||
: "unknown words"}
|
: "unknown words"}
|
||||||
|
|
|
@ -2,14 +2,20 @@ import styled from "styled-components"
|
||||||
import { Link } from "react-router-dom"
|
import { Link } from "react-router-dom"
|
||||||
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
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"
|
import theming from "../../styles/theming"
|
||||||
|
|
||||||
const StyledNextPrevContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
size: 100%;
|
size: 100%;
|
||||||
|
|
||||||
|
line-height: 1rem;
|
||||||
`
|
`
|
||||||
|
|
||||||
const StyledLink = styled(Link)`
|
const StyledLink = styled(Link)`
|
||||||
|
@ -23,7 +29,6 @@ const StyledLink = styled(Link)`
|
||||||
|
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
margin-top: 2rem;
|
|
||||||
|
|
||||||
line-height: 1rem;
|
line-height: 1rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -45,16 +50,19 @@ const StyledDisabledLink = styled.div`
|
||||||
|
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
width: 2rem;
|
width: 2rem;
|
||||||
margin-top: 2rem;
|
|
||||||
|
|
||||||
line-height: 1rem;
|
line-height: 1rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
`
|
`
|
||||||
|
|
||||||
const NextPrevButtons = (props: { prevURL?: string; nextURL?: string }) => {
|
const SeriesControlButtons = (props: {
|
||||||
|
seriesHome: string
|
||||||
|
prevURL?: string
|
||||||
|
nextURL?: string
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<StyledNextPrevContainer>
|
<StyledContainer>
|
||||||
{props.prevURL ? (
|
{props.prevURL ? (
|
||||||
<StyledLink to={props.prevURL}>
|
<StyledLink to={props.prevURL}>
|
||||||
<FontAwesomeIcon icon={faArrowLeft} />
|
<FontAwesomeIcon icon={faArrowLeft} />
|
||||||
|
@ -64,6 +72,11 @@ const NextPrevButtons = (props: { prevURL?: string; nextURL?: string }) => {
|
||||||
<FontAwesomeIcon icon={faArrowLeft} />
|
<FontAwesomeIcon icon={faArrowLeft} />
|
||||||
</StyledDisabledLink>
|
</StyledDisabledLink>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<StyledLink to={props.seriesHome}>
|
||||||
|
<FontAwesomeIcon icon={faListUl} />
|
||||||
|
</StyledLink>
|
||||||
|
|
||||||
{props.nextURL ? (
|
{props.nextURL ? (
|
||||||
<StyledLink to={props.nextURL}>
|
<StyledLink to={props.nextURL}>
|
||||||
<FontAwesomeIcon icon={faArrowRight} />
|
<FontAwesomeIcon icon={faArrowRight} />
|
||||||
|
@ -73,8 +86,8 @@ const NextPrevButtons = (props: { prevURL?: string; nextURL?: string }) => {
|
||||||
<FontAwesomeIcon icon={faArrowRight} />
|
<FontAwesomeIcon icon={faArrowRight} />
|
||||||
</StyledDisabledLink>
|
</StyledDisabledLink>
|
||||||
)}
|
)}
|
||||||
</StyledNextPrevContainer>
|
</StyledContainer>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NextPrevButtons
|
export default SeriesControlButtons
|
|
@ -7,13 +7,14 @@ import { PageData, Map } from "../../../types/types"
|
||||||
|
|
||||||
import GithubLinkIcon from "../../components/GithubLinkIcon"
|
import GithubLinkIcon from "../../components/GithubLinkIcon"
|
||||||
import MainContent from "../../components/MainContent"
|
import MainContent from "../../components/MainContent"
|
||||||
|
import PostCard from "../../components/PostCard"
|
||||||
import Loading from "../../components/Loading"
|
import Loading from "../../components/Loading"
|
||||||
import TagList from "../../components/TagList"
|
import TagList from "../../components/TagList"
|
||||||
import Badge from "../../components/Badge"
|
import Badge from "../../components/Badge"
|
||||||
import Tag from "../../components/Tag"
|
import Tag from "../../components/Tag"
|
||||||
import NotFound from "../NotFound"
|
import NotFound from "../NotFound"
|
||||||
|
|
||||||
import NextPrevButtons from "./NextPrevButtons"
|
import SeriesControlButtons from "./SeriesControlButtons"
|
||||||
import Meta from "./Meta"
|
import Meta from "./Meta"
|
||||||
import Toc from "./Toc"
|
import Toc from "./Toc"
|
||||||
|
|
||||||
|
@ -47,6 +48,7 @@ const ProjectImage = styled.img`
|
||||||
enum PageType {
|
enum PageType {
|
||||||
POST,
|
POST,
|
||||||
SERIES,
|
SERIES,
|
||||||
|
SERIES_HOME,
|
||||||
PORTFOLIO_PROJECT,
|
PORTFOLIO_PROJECT,
|
||||||
UNSEARCHABLE,
|
UNSEARCHABLE,
|
||||||
}
|
}
|
||||||
|
@ -65,7 +67,15 @@ const fetchContent = async (pageType: PageType, url: string) => {
|
||||||
|
|
||||||
const categorizePageType = (url: string): PageType => {
|
const categorizePageType = (url: string): PageType => {
|
||||||
if (url.startsWith("/post")) return PageType.POST
|
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
|
if (url.startsWith("/portfolio")) return PageType.PORTFOLIO_PROJECT
|
||||||
|
|
||||||
return PageType.UNSEARCHABLE
|
return PageType.UNSEARCHABLE
|
||||||
|
@ -80,22 +90,25 @@ const Page = () => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const url = location.pathname.replace(/\/$/, "") // remove trailing slash
|
const url = location.pathname.replace(/\/$/, "") // remove trailing slash
|
||||||
const _pageType = categorizePageType(url)
|
const pageType = categorizePageType(url)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if url is a valid one
|
* Test if url is a valid one
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let show404 = false
|
let show404 = false
|
||||||
switch (_pageType) {
|
switch (pageType) {
|
||||||
case PageType.POST: {
|
case PageType.POST: {
|
||||||
if (!map.posts[url]) show404 = true
|
if (!map.posts[url]) show404 = true
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case PageType.SERIES_HOME:
|
||||||
case PageType.SERIES: {
|
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
|
break
|
||||||
}
|
}
|
||||||
|
@ -131,7 +144,18 @@ const Page = () => {
|
||||||
toc: undefined,
|
toc: undefined,
|
||||||
content: "No content",
|
content: "No content",
|
||||||
|
|
||||||
|
// series
|
||||||
|
|
||||||
seriesHome: "",
|
seriesHome: "",
|
||||||
|
prev: "",
|
||||||
|
next: "",
|
||||||
|
|
||||||
|
// series home
|
||||||
|
|
||||||
|
order: [],
|
||||||
|
length: 0,
|
||||||
|
|
||||||
|
// portfolio
|
||||||
|
|
||||||
image: "",
|
image: "",
|
||||||
overview: "",
|
overview: "",
|
||||||
|
@ -139,13 +163,13 @@ const Page = () => {
|
||||||
repo: "",
|
repo: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchContent(_pageType, url).then((fetched_content) => {
|
fetchContent(pageType, url).then((fetched_content) => {
|
||||||
if (!fetched_content) {
|
if (!fetched_content) {
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_pageType) {
|
switch (pageType) {
|
||||||
case PageType.POST: {
|
case PageType.POST: {
|
||||||
const post = map.posts[url]
|
const post = map.posts[url]
|
||||||
|
|
||||||
|
@ -190,6 +214,21 @@ const Page = () => {
|
||||||
break
|
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: {
|
case PageType.PORTFOLIO_PROJECT: {
|
||||||
const data =
|
const data =
|
||||||
portfolio.projects[url as keyof typeof portfolio.projects]
|
portfolio.projects[url as keyof typeof portfolio.projects]
|
||||||
|
@ -214,7 +253,11 @@ const Page = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setPageType(_pageType)
|
/**
|
||||||
|
* Apply result
|
||||||
|
*/
|
||||||
|
|
||||||
|
setPageType(pageType)
|
||||||
setPageData(pageData)
|
setPageData(pageData)
|
||||||
|
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
|
@ -241,7 +284,11 @@ const Page = () => {
|
||||||
<MainContent>
|
<MainContent>
|
||||||
{/* next/previous series post buttons */}
|
{/* next/previous series post buttons */}
|
||||||
{pageType == PageType.SERIES && (
|
{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 && (
|
{pageType == PageType.PORTFOLIO_PROJECT && pageData.repo && (
|
||||||
|
@ -273,9 +320,9 @@ const Page = () => {
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
{/* Post metadata */}
|
{/* Post metadata */}
|
||||||
{[PageType.POST, PageType.SERIES].includes(pageType) && (
|
{[PageType.POST, PageType.SERIES, PageType.SERIES_HOME].includes(
|
||||||
<Meta fetchedPage={pageData} />
|
pageType
|
||||||
)}
|
) && <Meta fetchedPage={pageData} />}
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
@ -294,6 +341,21 @@ const Page = () => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</MainContent>
|
</MainContent>
|
||||||
|
|
||||||
|
{/* series post list */}
|
||||||
|
|
||||||
|
{pageType == PageType.SERIES_HOME &&
|
||||||
|
pageData.order.map((post) => {
|
||||||
|
return (
|
||||||
|
<PostCard
|
||||||
|
key={post}
|
||||||
|
postData={{
|
||||||
|
url: post,
|
||||||
|
...map.posts[post],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,12 +62,18 @@ export interface PageData {
|
||||||
toc?: string
|
toc?: string
|
||||||
content: string
|
content: string
|
||||||
|
|
||||||
// series-specific data
|
// series
|
||||||
|
|
||||||
seriesHome: string
|
seriesHome: string
|
||||||
prev?: string
|
prev?: string
|
||||||
next?: string
|
next?: string
|
||||||
|
|
||||||
// portfolio-specific data
|
// series home
|
||||||
|
|
||||||
|
order: string[]
|
||||||
|
length: number
|
||||||
|
|
||||||
|
// portfolio
|
||||||
|
|
||||||
image: string // image url
|
image: string // image url
|
||||||
overview: string
|
overview: string
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue