diff --git a/source/src/pages/Page/Meta.tsx b/source/src/pages/Page/Meta.tsx index a358093..7a48858 100644 --- a/source/src/pages/Page/Meta.tsx +++ b/source/src/pages/Page/Meta.tsx @@ -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 ( + {/* posts count */} + +    + {props.fetchedPage.length + ? props.fetchedPage.length + " posts" + : "no posts"} +      + {/* date */} -     +    {props.fetchedPage.date || "Unknown date"}      + {/* read time */} -     +    {props.fetchedPage.readTime ? props.fetchedPage.readTime + " read" : "unknown length"}      + {/* word count */} -     +    {props.fetchedPage.wordCount ? props.fetchedPage.wordCount + " words" : "unknown words"} diff --git a/source/src/pages/Page/NextPrevButtons.tsx b/source/src/pages/Page/SeriesControlButtons.tsx similarity index 76% rename from source/src/pages/Page/NextPrevButtons.tsx rename to source/src/pages/Page/SeriesControlButtons.tsx index 39b4037..f060bb8 100644 --- a/source/src/pages/Page/NextPrevButtons.tsx +++ b/source/src/pages/Page/SeriesControlButtons.tsx @@ -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 ( - + {props.prevURL ? ( @@ -64,6 +72,11 @@ const NextPrevButtons = (props: { prevURL?: string; nextURL?: string }) => { )} + + + + + {props.nextURL ? ( @@ -73,8 +86,8 @@ const NextPrevButtons = (props: { prevURL?: string; nextURL?: string }) => { )} - + ) } -export default NextPrevButtons +export default SeriesControlButtons diff --git a/source/src/pages/Page/index.tsx b/source/src/pages/Page/index.tsx index 59bd692..1708d59 100644 --- a/source/src/pages/Page/index.tsx +++ b/source/src/pages/Page/index.tsx @@ -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 = () => { {/* next/previous series post buttons */} {pageType == PageType.SERIES && ( - + )} {pageType == PageType.PORTFOLIO_PROJECT && pageData.repo && ( @@ -273,9 +320,9 @@ const Page = () => {
{/* Post metadata */} - {[PageType.POST, PageType.SERIES].includes(pageType) && ( - - )} + {[PageType.POST, PageType.SERIES, PageType.SERIES_HOME].includes( + pageType + ) && }
@@ -294,6 +341,21 @@ const Page = () => { }} />
+ + {/* series post list */} + + {pageType == PageType.SERIES_HOME && + pageData.order.map((post) => { + return ( + + ) + })} ) } diff --git a/source/types/types.ts b/source/types/types.ts index 1cbd2f0..6decfde 100644 --- a/source/types/types.ts +++ b/source/types/types.ts @@ -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