import React from "react" import { Helmet } from "react-helmet-async" import { Link } from "react-router-dom" import styled from "styled-components" import { HashLink } from "react-router-hash-link" import { Collapse } from "react-collapse" import storage from "local-storage-fallback" import theming from "../theming" import Tag from "../components/Tag" import TagList from "../components/TagList" import NotFound from "./NotFound" import Spinner from "../components/Spinner" import map from "../data/map.json" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" import { faBook, faCalendar, faCaretDown, faCaretUp, faHourglass, } from "@fortawesome/free-solid-svg-icons" const StyledTitle = styled.h1` margin-bottom: 1rem; ` const StyledNextPrevContainer = styled.div` display: flex; justify-content: space-between; size: 100%; ` const StyledLink = styled(Link)` ${theming.styles.navbarButtonStyle} background-color: ${(props) => theming.theme(props.theme.currentTheme, { light: "#EEEEEE", dark: "#202225", })}; height: 1rem; width: 2rem; margin-top: 2rem; line-height: 1rem; text-align: center; ` const StyledDisabledLink = styled.div` font-size: 1rem; border-radius: 0.5rem; float: left; padding: 14px 16px; text-decoration: none; transition: transform 0.1s linear; color: grey; background-color: ${(props) => theming.theme(props.theme.currentTheme, { light: "#EEEEEE", dark: "#202225", })}; height: 1rem; width: 2rem; margin-top: 2rem; line-height: 1rem; text-align: center; user-select: none; ` const StyledTocToggleButton = styled.button` border: none; text-align: left; background-color: rgba(0, 0, 0, 0); width: 100%; padding: 0.5rem; color: ${(props) => theming.theme(props.theme.currentTheme, { light: "black", dark: "white", })}; ` const StyledCollapseContainer = styled.div` * { transition: height 200ms ease-out; } ` function parseToc(json) { return (
    {json.map((elem) => ( // elem: content, i, lvl
  1. {elem.content}
  2. ))}
) } interface PageProps {} interface PageState { // eslint-disable-next-line @typescript-eslint/no-explicit-any fetchedPage: any isUnsearchable: boolean isSeries: boolean seriesData: { seriesHome: string prev: string | null next: string | null } | null isTocOpened: boolean loading: boolean } interface NextPrevProps { prevURL: string | null nextURL: string | null } class NextPrev extends React.Component { render() { return ( {this.props.prevURL ? ( prev ) : ( prev )} {this.props.nextURL ? ( next ) : ( next )} ) } } export default class Page extends React.Component { constructor(props) { super(props) this.state = { fetchedPage: undefined, isUnsearchable: false, isSeries: false, seriesData: null, isTocOpened: storage.getItem("isTocOpened") == "true", loading: true, } } componentDidUpdate(_, prevState) { if (this.state.isTocOpened !== prevState.isTocOpened) { storage.setItem("isTocOpened", this.state.isTocOpened.toString()) } } async componentDidMount() { let _isUnsearchable = false let _isSeries = false const url = location.pathname.replace(/\/$/, "") // remove trailing slash if (url.startsWith("/series")) _isSeries = true if (_isSeries) { const seriesURL = url.slice(0, url.lastIndexOf("/")) if (seriesURL in map.series) { const _curr: number = map.series[seriesURL].order.indexOf(url) let _prev: number | null = _curr - 1 let _next: number | null = _curr + 1 if (_prev < 0) _prev = null if (_next > map.series[seriesURL].order.length - 1) _next = null this.setState({ seriesData: { seriesHome: seriesURL, prev: _prev != null ? map.series[seriesURL].order[_prev] : null, next: _next != null ? map.series[seriesURL].order[_next] : null, }, }) } } // fetch page let fetchedPage = map.posts[url] if (!fetchedPage) { fetchedPage = map.unsearchable[url] _isUnsearchable = true this.setState({ isUnsearchable: true }) if (!fetchedPage) { this.setState({ loading: false, }) return } } const fetched_content = _isUnsearchable ? await import(`../data/content/unsearchable${url}.json`) : await import(`../data/content${url}.json`) fetchedPage.content = fetched_content.content ? fetched_content.content : "No content" fetchedPage.toc = fetched_content.toc ? parseToc(fetched_content.toc) : undefined fetchedPage.title = fetchedPage?.title ? fetchedPage.title : "No title" if (!_isUnsearchable) { fetchedPage.date = fetchedPage?.date ? fetchedPage.date : "Unknown date" } this.setState({ isSeries: _isSeries, fetchedPage: fetchedPage, loading: false, }) } render() { if (this.state.loading) { return } else { if (!this.state.fetchedPage) return return ( <> pomp | {this.state.fetchedPage.title}
{this.state.isSeries ? ( ) : (
)} {this.state.fetchedPage.title} {/* Post tags */} {this.state.fetchedPage.tags ? ( this.state.fetchedPage.tags.map((tag) => { return ( ) }) ) : ( <> )}
{this.state.isUnsearchable ? ( <> ) : ( <> {" "} Published on {this.state.fetchedPage.date}      {" "} {this.state.fetchedPage.readTime} read      {" "} {this.state.fetchedPage.wordCount} words )}
{/* Horizontal Separator */}
{ // add table of contents if it exists this.state.fetchedPage.toc && ( <> { this.setState({ isTocOpened: !this.state.isTocOpened, }) }} > Table of Content {this.state.isTocOpened ? ( ) : ( )}
{this.state.fetchedPage.toc}

) }
) } } }