rewrote page logic and renamed type
This commit is contained in:
parent
67241cf3cb
commit
d31dff53ae
3 changed files with 190 additions and 73 deletions
|
@ -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} />
|
||||||
|
|
|
@ -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) {
|
/**
|
||||||
|
* Test if url is a valid one
|
||||||
|
*/
|
||||||
|
|
||||||
|
let show404 = false
|
||||||
|
switch (_pageType) {
|
||||||
|
case PageType.POST: {
|
||||||
|
if (!map.posts[url]) show404 = true
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case PageType.SERIES: {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show404) {
|
||||||
|
setIsLoading(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get page data
|
||||||
|
*/
|
||||||
|
|
||||||
|
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)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (_pageType) {
|
||||||
|
case PageType.POST: {
|
||||||
|
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.SERIES: {
|
||||||
const seriesURL = url.slice(0, url.lastIndexOf("/"))
|
const seriesURL = url.slice(0, url.lastIndexOf("/"))
|
||||||
if (seriesURL in map.series) {
|
|
||||||
const _curr: number = map.series[seriesURL].order.indexOf(url)
|
const curr = map.series[seriesURL].order.indexOf(url)
|
||||||
const _prev = _curr - 1
|
const prev = curr - 1
|
||||||
const _next = _curr + 1
|
const next = curr + 1
|
||||||
|
|
||||||
setSeriesData({
|
setSeriesData({
|
||||||
seriesHome: seriesURL,
|
seriesHome: seriesURL,
|
||||||
prev:
|
prev:
|
||||||
_prev >= 0
|
prev >= 0
|
||||||
? map.series[seriesURL].order[_prev]
|
? map.series[seriesURL].order[prev]
|
||||||
: undefined,
|
: undefined,
|
||||||
next:
|
next:
|
||||||
_next < map.series[seriesURL].order.length
|
next < map.series[seriesURL].order.length
|
||||||
? map.series[seriesURL].order[_next]
|
? map.series[seriesURL].order[next]
|
||||||
: undefined,
|
: 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch page
|
setPageType(_pageType)
|
||||||
const MapPost = map.posts[url]
|
setPageData(pageData)
|
||||||
const fetchedPage: FetchedPage = {
|
|
||||||
...MapPost,
|
|
||||||
toc: undefined,
|
|
||||||
content: "",
|
|
||||||
tags: [] as string[],
|
|
||||||
}
|
|
||||||
|
|
||||||
let _isUnsearchable = false
|
|
||||||
if (!MapPost) {
|
|
||||||
_isUnsearchable = true
|
|
||||||
setIsPageUnsearchable(_isUnsearchable)
|
|
||||||
|
|
||||||
if (!map.unsearchable[url]) {
|
|
||||||
setIsLoading(false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchContent(_isUnsearchable, url).then((fetched_content) => {
|
|
||||||
fetchedPage.content = fetched_content.content || "No content"
|
|
||||||
fetchedPage.toc = fetched_content.toc
|
|
||||||
fetchedPage.title = _isUnsearchable
|
|
||||||
? map.unsearchable[url].title
|
|
||||||
: fetchedPage?.title || "No title"
|
|
||||||
|
|
||||||
if (!_isUnsearchable)
|
|
||||||
fetchedPage.date = fetchedPage?.date || "Unknown date"
|
|
||||||
|
|
||||||
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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue