rewrote page logic and renamed type

This commit is contained in:
Kim, Jimin 2022-01-08 19:30:10 +09:00
parent 67241cf3cb
commit d31dff53ae
3 changed files with 190 additions and 73 deletions

View file

@ -6,7 +6,7 @@ import {
faHourglass, faHourglass,
} from "@fortawesome/free-solid-svg-icons" } from "@fortawesome/free-solid-svg-icons"
import { FetchedPage } from "../../../types/types" import { PageData } from "../../../types/types"
import theming from "../../styles/theming" import theming from "../../styles/theming"
const StyledMetaContainer = styled.div` const StyledMetaContainer = styled.div`
@ -17,7 +17,7 @@ const StyledMetaContainer = styled.div`
})}; })};
` `
const Meta = (props: { fetchedPage: FetchedPage }) => { const Meta = (props: { fetchedPage: PageData }) => {
return ( return (
<StyledMetaContainer> <StyledMetaContainer>
<FontAwesomeIcon icon={faCalendar} /> <FontAwesomeIcon icon={faCalendar} />

View file

@ -3,7 +3,7 @@ import { Helmet } from "react-helmet-async"
import { useLocation } from "react-router-dom" import { useLocation } from "react-router-dom"
import styled from "styled-components" import styled from "styled-components"
import { FetchedPage, Map } from "../../../types/types" import { PageData, Map } from "../../../types/types"
import MainContent from "../../components/MainContent" import MainContent from "../../components/MainContent"
import Loading from "../../components/Loading" import Loading from "../../components/Loading"
@ -15,6 +15,7 @@ import NextPrevButtons from "./NextPrevButtons"
import Meta from "./Meta" import Meta from "./Meta"
import Toc from "./Toc" import Toc from "./Toc"
import portfolio from "../../data/portfolio.json"
import _map from "../../data/map.json" import _map from "../../data/map.json"
import { useEffect } from "react" import { useEffect } from "react"
@ -24,105 +25,219 @@ const StyledTitle = styled.h1`
margin-bottom: 1rem; margin-bottom: 1rem;
` `
enum PageType {
POST,
SERIES,
PORTFOLIO_PROJECT,
UNSEARCHABLE,
}
interface SeriesData { interface SeriesData {
seriesHome: string seriesHome: string
prev?: string prev?: string
next?: string next?: string
} }
const fetchContent = async (pageType: PageType, url: string) => {
try {
if (pageType == PageType.UNSEARCHABLE) {
return await import(`../../data/content/unsearchable${url}.json`)
}
return await import(`../../data/content${url}.json`)
} catch (err) {
return
}
}
const categorizePageType = (url: string): PageType => {
if (url.startsWith("/post")) return PageType.POST
if (url.startsWith("/series")) return PageType.SERIES
if (url.startsWith("/portfolio")) return PageType.PORTFOLIO_PROJECT
return PageType.UNSEARCHABLE
}
const Page = () => { const Page = () => {
const [fetchedPage, setFetchPage] = useState<FetchedPage | undefined>( const location = useLocation()
undefined
) const [pageData, setPageData] = useState<PageData | undefined>(undefined)
const [isPageUnsearchable, setIsPageUnsearchable] = useState(false) const [pageType, setPageType] = useState<PageType>(PageType.POST)
const [isSeries, setIsSeries] = useState(false) const [isLoading, setIsLoading] = useState(true)
// only used when the page is a series post
// todo: merge with pageData
const [seriesData, setSeriesData] = useState<SeriesData | undefined>( const [seriesData, setSeriesData] = useState<SeriesData | undefined>(
undefined undefined
) )
const [isLoading, setIsLoading] = useState(true)
const location = useLocation()
const fetchContent = async (
isContentUnsearchable: boolean,
url: string
) => {
return isContentUnsearchable
? await import(`../../data/content/unsearchable${url}.json`)
: await import(`../../data/content${url}.json`)
}
useEffect(() => { useEffect(() => {
let _isSeries = false
const url = location.pathname.replace(/\/$/, "") // remove trailing slash const url = location.pathname.replace(/\/$/, "") // remove trailing slash
if (url.startsWith("/series")) _isSeries = true const _pageType = categorizePageType(url)
if (_isSeries) { /**
const seriesURL = url.slice(0, url.lastIndexOf("/")) * Test if url is a valid one
if (seriesURL in map.series) { */
const _curr: number = map.series[seriesURL].order.indexOf(url)
const _prev = _curr - 1
const _next = _curr + 1
setSeriesData({ let show404 = false
seriesHome: seriesURL, switch (_pageType) {
prev: case PageType.POST: {
_prev >= 0 if (!map.posts[url]) show404 = true
? map.series[seriesURL].order[_prev]
: undefined, break
next: }
_next < map.series[seriesURL].order.length
? map.series[seriesURL].order[_next] case PageType.SERIES: {
: undefined, if (!(url.slice(0, url.lastIndexOf("/")) in map.series))
}) show404 = true
break
}
case PageType.PORTFOLIO_PROJECT: {
if (!(url in portfolio.projects)) show404 = true
break
}
case PageType.UNSEARCHABLE: {
if (!map.unsearchable[url]) show404 = true
break
} }
} }
// fetch page if (show404) {
const MapPost = map.posts[url] setIsLoading(false)
const fetchedPage: FetchedPage = { return
...MapPost,
toc: undefined,
content: "",
tags: [] as string[],
} }
let _isUnsearchable = false /**
if (!MapPost) { * Get page data
_isUnsearchable = true */
setIsPageUnsearchable(_isUnsearchable)
if (!map.unsearchable[url]) { const pageData: PageData = {
title: "No title",
date: "Unknown date",
readTime: "Unknown read time",
wordCount: 0,
tags: [],
toc: undefined,
content: "No content",
}
fetchContent(_pageType, url).then((fetched_content) => {
if (!fetched_content) {
setIsLoading(false) setIsLoading(false)
return return
} }
}
fetchContent(_isUnsearchable, url).then((fetched_content) => { switch (_pageType) {
fetchedPage.content = fetched_content.content || "No content" case PageType.POST: {
fetchedPage.toc = fetched_content.toc const post = map.posts[url]
fetchedPage.title = _isUnsearchable
? map.unsearchable[url].title
: fetchedPage?.title || "No title"
if (!_isUnsearchable) pageData.content = fetched_content.content
fetchedPage.date = fetchedPage?.date || "Unknown date" pageData.toc = fetched_content.toc
pageData.title = post.title
pageData.date = post.date
pageData.readTime = post.readTime
pageData.wordCount = post.wordCount
pageData.tags = post.tags || []
break
}
case PageType.SERIES: {
const seriesURL = url.slice(0, url.lastIndexOf("/"))
const curr = map.series[seriesURL].order.indexOf(url)
const prev = curr - 1
const next = curr + 1
setSeriesData({
seriesHome: seriesURL,
prev:
prev >= 0
? map.series[seriesURL].order[prev]
: undefined,
next:
next < map.series[seriesURL].order.length
? map.series[seriesURL].order[next]
: undefined,
})
const post = map.posts[url]
pageData.content = fetched_content.content
pageData.toc = fetched_content.toc
pageData.title = post.title
pageData.date = post.date
pageData.readTime = post.readTime
pageData.wordCount = post.wordCount
pageData.tags = post.tags || []
break
}
case PageType.PORTFOLIO_PROJECT: {
const data =
portfolio.projects[
url as keyof typeof portfolio.projects
]
console.log(fetched_content)
pageData.content = fetched_content.content
pageData.toc = fetched_content.toc
pageData.title = data.name
// todo: add portfolio data
/*
"image": "/img/portfolio/developomp.com.png",
"overview": "my website for blogging, portfolio, and resume.",
"badges": [
"typescript",
"javascript",
"nodedotjs",
"firebase",
"react",
"html5",
"css3"
],
"repo": "https://github.com/developomp/developomp-site"
*/
break
}
case PageType.UNSEARCHABLE: {
pageData.title = map.unsearchable[url].title
pageData.content = fetched_content.content
break
}
}
setPageType(_pageType)
setPageData(pageData)
setIsSeries(_isSeries)
setFetchPage(fetchedPage)
setIsLoading(false) setIsLoading(false)
}) })
}, [location]) }, [location])
if (isLoading) return <Loading /> if (isLoading) return <Loading />
if (!fetchedPage) return <NotFound /> if (!pageData) return <NotFound />
return ( return (
<> <>
<Helmet> <Helmet>
<title>pomp | {fetchedPage.title}</title> <title>pomp | {pageData.title}</title>
<meta property="og:title" content={fetchedPage.title} /> <meta property="og:title" content={pageData.title} />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta <meta
property="og:image" property="og:image"
@ -131,7 +246,7 @@ const Page = () => {
</Helmet> </Helmet>
<MainContent> <MainContent>
{isSeries ? ( {pageType == PageType.SERIES ? (
<NextPrevButtons <NextPrevButtons
prevURL={seriesData?.prev} prevURL={seriesData?.prev}
nextURL={seriesData?.next} nextURL={seriesData?.next}
@ -139,15 +254,15 @@ const Page = () => {
) : ( ) : (
<br /> <br />
)} )}
<StyledTitle>{fetchedPage.title}</StyledTitle> <StyledTitle>{pageData.title}</StyledTitle>
<small> <small>
{/* Post tags */} {/* Post tags */}
{!!fetchedPage.tags.length && ( {!!pageData.tags.length && (
<TagList direction="left"> <TagList direction="left">
{fetchedPage.tags.map((tag) => { {pageData.tags.map((tag) => {
return ( return (
<td key={fetchedPage?.title + tag}> <td key={pageData?.title + tag}>
<Tag text={tag} /> <Tag text={tag} />
</td> </td>
) )
@ -158,18 +273,20 @@ const Page = () => {
<br /> <br />
{/* Post metadata */} {/* Post metadata */}
{!isPageUnsearchable && <Meta fetchedPage={fetchedPage} />} {pageType != PageType.UNSEARCHABLE && (
<Meta fetchedPage={pageData} />
)}
</small> </small>
<hr /> <hr />
{/* add table of contents if it exists */} {/* add table of contents if it exists */}
<Toc data={fetchedPage.toc} /> <Toc data={pageData.toc} />
{/* page content */} {/* page content */}
<div <div
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: fetchedPage.content, __html: pageData.content,
}} }}
/> />
</MainContent> </MainContent>

View file

@ -53,7 +53,7 @@ export interface PostData {
tags?: string[] tags?: string[]
} }
export interface FetchedPage { export interface PageData {
title: string title: string
date: string date: string
readTime: string readTime: string