split page to smaller components
This commit is contained in:
parent
150311472e
commit
fd67ff2114
4 changed files with 192 additions and 172 deletions
42
source/src/pages/Page/Meta.tsx
Normal file
42
source/src/pages/Page/Meta.tsx
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import styled from "styled-components"
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||||
|
import {
|
||||||
|
faBook,
|
||||||
|
faCalendar,
|
||||||
|
faHourglass,
|
||||||
|
} from "@fortawesome/free-solid-svg-icons"
|
||||||
|
|
||||||
|
import { FetchedPage } from "../../types/typings"
|
||||||
|
import theming from "../../styles/theming"
|
||||||
|
|
||||||
|
const StyledMetaContainer = styled.div`
|
||||||
|
color: ${(props) =>
|
||||||
|
theming.theme(props.theme.currentTheme, {
|
||||||
|
light: "#555",
|
||||||
|
dark: "#CCC",
|
||||||
|
})};
|
||||||
|
`
|
||||||
|
|
||||||
|
const Meta = (props: { fetchedPage: FetchedPage }) => {
|
||||||
|
return (
|
||||||
|
<StyledMetaContainer>
|
||||||
|
<FontAwesomeIcon icon={faCalendar} />
|
||||||
|
|
||||||
|
{props.fetchedPage.date || "Unknown date"}
|
||||||
|
|
||||||
|
<FontAwesomeIcon icon={faHourglass} />
|
||||||
|
|
||||||
|
{props.fetchedPage.readTime
|
||||||
|
? props.fetchedPage.readTime + " read"
|
||||||
|
: "unknown length"}
|
||||||
|
|
||||||
|
<FontAwesomeIcon icon={faBook} />
|
||||||
|
|
||||||
|
{props.fetchedPage.wordCount
|
||||||
|
? props.fetchedPage.wordCount + " words"
|
||||||
|
: "unknown words"}
|
||||||
|
</StyledMetaContainer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Meta
|
69
source/src/pages/Page/NextPrevButtons.tsx
Normal file
69
source/src/pages/Page/NextPrevButtons.tsx
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
import styled from "styled-components"
|
||||||
|
import { Link } from "react-router-dom"
|
||||||
|
|
||||||
|
import theming from "../../styles/theming"
|
||||||
|
|
||||||
|
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 NextPrevButtons = (props: { prevURL?: string; nextURL?: string }) => {
|
||||||
|
return (
|
||||||
|
<StyledNextPrevContainer>
|
||||||
|
{props.prevURL ? (
|
||||||
|
<StyledLink to={props.prevURL}>prev</StyledLink>
|
||||||
|
) : (
|
||||||
|
<StyledDisabledLink>prev</StyledDisabledLink>
|
||||||
|
)}
|
||||||
|
{props.nextURL ? (
|
||||||
|
<StyledLink to={props.nextURL}>next</StyledLink>
|
||||||
|
) : (
|
||||||
|
<StyledDisabledLink>next</StyledDisabledLink>
|
||||||
|
)}
|
||||||
|
</StyledNextPrevContainer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NextPrevButtons
|
65
source/src/pages/Page/Toc.tsx
Normal file
65
source/src/pages/Page/Toc.tsx
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
import { Collapse } from "react-collapse"
|
||||||
|
import storage from "local-storage-fallback"
|
||||||
|
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||||
|
import { faCaretDown, faCaretUp } from "@fortawesome/free-solid-svg-icons"
|
||||||
|
import styled from "styled-components"
|
||||||
|
|
||||||
|
import theming from "../../styles/theming"
|
||||||
|
|
||||||
|
import { FetchedPage } from "../../types/typings"
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const Toc = (props: { fetchedPage: FetchedPage }) => {
|
||||||
|
const [isTocOpened, setIsTocOpened] = useState(
|
||||||
|
storage.getItem("isTocOpened") == "true"
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
storage.setItem("isTocOpened", isTocOpened.toString())
|
||||||
|
}, [isTocOpened])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<StyledTocToggleButton
|
||||||
|
onClick={() => {
|
||||||
|
setIsTocOpened((prev) => !prev)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<strong>Table of Content </strong>
|
||||||
|
{isTocOpened ? (
|
||||||
|
<FontAwesomeIcon icon={faCaretUp} />
|
||||||
|
) : (
|
||||||
|
<FontAwesomeIcon icon={faCaretDown} />
|
||||||
|
)}
|
||||||
|
</StyledTocToggleButton>
|
||||||
|
<StyledCollapseContainer>
|
||||||
|
<Collapse isOpened={isTocOpened}>
|
||||||
|
<div className="white-link">{props.fetchedPage.toc}</div>
|
||||||
|
</Collapse>
|
||||||
|
</StyledCollapseContainer>
|
||||||
|
<hr />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Toc
|
|
@ -1,31 +1,22 @@
|
||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import { Helmet } from "react-helmet-async"
|
import { Helmet } from "react-helmet-async"
|
||||||
import { Link, useLocation } from "react-router-dom"
|
import { useLocation } from "react-router-dom"
|
||||||
import styled from "styled-components"
|
import styled from "styled-components"
|
||||||
import { HashLink } from "react-router-hash-link"
|
import { HashLink } from "react-router-hash-link"
|
||||||
import { Collapse } from "react-collapse"
|
|
||||||
import storage from "local-storage-fallback"
|
|
||||||
|
|
||||||
import { TocElement, FetchedPage, Map } from "../types/typings"
|
import { TocElement, FetchedPage, Map } from "../../types/typings"
|
||||||
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
import MainContent from "../../components/MainContent"
|
||||||
import {
|
import Loading from "../../components/Loading"
|
||||||
faBook,
|
import TagList from "../../components/TagList"
|
||||||
faCalendar,
|
import Tag from "../../components/Tag"
|
||||||
faCaretDown,
|
import NotFound from "../NotFound"
|
||||||
faCaretUp,
|
|
||||||
faHourglass,
|
|
||||||
} from "@fortawesome/free-solid-svg-icons"
|
|
||||||
|
|
||||||
import MainContent from "../components/MainContent"
|
import NextPrevButtons from "./NextPrevButtons"
|
||||||
import Loading from "../components/Loading"
|
import Meta from "./Meta"
|
||||||
import TagList from "../components/TagList"
|
import Toc from "./Toc"
|
||||||
import Tag from "../components/Tag"
|
|
||||||
import NotFound from "./NotFound"
|
|
||||||
|
|
||||||
import theming from "../styles/theming"
|
import _map from "../../data/map.json"
|
||||||
|
|
||||||
import _map from "../data/map.json"
|
|
||||||
import { useEffect } from "react"
|
import { useEffect } from "react"
|
||||||
|
|
||||||
const map: Map = _map
|
const map: Map = _map
|
||||||
|
@ -38,79 +29,6 @@ const StyledTitle = styled.h1`
|
||||||
margin-bottom: 1rem;
|
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;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const StyledMetaContainer = styled.div`
|
|
||||||
color: ${(props) =>
|
|
||||||
theming.theme(props.theme.currentTheme, {
|
|
||||||
light: "#555",
|
|
||||||
dark: "#CCC",
|
|
||||||
})};
|
|
||||||
`
|
|
||||||
|
|
||||||
function parseToc(tocData: TocElement[]) {
|
function parseToc(tocData: TocElement[]) {
|
||||||
return (
|
return (
|
||||||
<ol>
|
<ol>
|
||||||
|
@ -126,78 +44,6 @@ function parseToc(tocData: TocElement[]) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const NextPrevButton = (props: { prevURL?: string; nextURL?: string }) => {
|
|
||||||
return (
|
|
||||||
<StyledNextPrevContainer>
|
|
||||||
{props.prevURL ? (
|
|
||||||
<StyledLink to={props.prevURL}>prev</StyledLink>
|
|
||||||
) : (
|
|
||||||
<StyledDisabledLink>prev</StyledDisabledLink>
|
|
||||||
)}
|
|
||||||
{props.nextURL ? (
|
|
||||||
<StyledLink to={props.nextURL}>next</StyledLink>
|
|
||||||
) : (
|
|
||||||
<StyledDisabledLink>next</StyledDisabledLink>
|
|
||||||
)}
|
|
||||||
</StyledNextPrevContainer>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const PostMeta = (props: { fetchedPage: FetchedPage }) => {
|
|
||||||
return (
|
|
||||||
<StyledMetaContainer>
|
|
||||||
<FontAwesomeIcon icon={faCalendar} />
|
|
||||||
|
|
||||||
{props.fetchedPage.date || "Unknown date"}
|
|
||||||
|
|
||||||
<FontAwesomeIcon icon={faHourglass} />
|
|
||||||
|
|
||||||
{props.fetchedPage.readTime
|
|
||||||
? props.fetchedPage.readTime + " read"
|
|
||||||
: "unknown length"}
|
|
||||||
|
|
||||||
<FontAwesomeIcon icon={faBook} />
|
|
||||||
|
|
||||||
{props.fetchedPage.wordCount
|
|
||||||
? props.fetchedPage.wordCount + " words"
|
|
||||||
: "unknown words"}
|
|
||||||
</StyledMetaContainer>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const PageTOC = (props: { fetchedPage: FetchedPage }) => {
|
|
||||||
const [isTocOpened, setIsTocOpened] = useState(
|
|
||||||
storage.getItem("isTocOpened") == "true"
|
|
||||||
)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
storage.setItem("isTocOpened", isTocOpened.toString())
|
|
||||||
}, [isTocOpened])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<StyledTocToggleButton
|
|
||||||
onClick={() => {
|
|
||||||
setIsTocOpened((prev) => !prev)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<strong>Table of Content </strong>
|
|
||||||
{isTocOpened ? (
|
|
||||||
<FontAwesomeIcon icon={faCaretUp} />
|
|
||||||
) : (
|
|
||||||
<FontAwesomeIcon icon={faCaretDown} />
|
|
||||||
)}
|
|
||||||
</StyledTocToggleButton>
|
|
||||||
<StyledCollapseContainer>
|
|
||||||
<Collapse isOpened={isTocOpened}>
|
|
||||||
<div className="white-link">{props.fetchedPage.toc}</div>
|
|
||||||
</Collapse>
|
|
||||||
</StyledCollapseContainer>
|
|
||||||
<hr />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SeriesData {
|
interface SeriesData {
|
||||||
seriesHome: string
|
seriesHome: string
|
||||||
prev?: string
|
prev?: string
|
||||||
|
@ -221,8 +67,8 @@ const Page = () => {
|
||||||
url: string
|
url: string
|
||||||
) => {
|
) => {
|
||||||
return isContentUnsearchable
|
return isContentUnsearchable
|
||||||
? await import(`../data/content/unsearchable${url}.json`)
|
? await import(`../../data/content/unsearchable${url}.json`)
|
||||||
: await import(`../data/content${url}.json`)
|
: await import(`../../data/content${url}.json`)
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -315,7 +161,7 @@ const Page = () => {
|
||||||
|
|
||||||
<StyledPage>
|
<StyledPage>
|
||||||
{isSeries ? (
|
{isSeries ? (
|
||||||
<NextPrevButton
|
<NextPrevButtons
|
||||||
prevURL={seriesData?.prev}
|
prevURL={seriesData?.prev}
|
||||||
nextURL={seriesData?.next}
|
nextURL={seriesData?.next}
|
||||||
/>
|
/>
|
||||||
|
@ -341,16 +187,14 @@ const Page = () => {
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
{/* Post metadata */}
|
{/* Post metadata */}
|
||||||
{!isPageUnsearchable && (
|
{!isPageUnsearchable && <Meta fetchedPage={fetchedPage} />}
|
||||||
<PostMeta fetchedPage={fetchedPage} />
|
|
||||||
)}
|
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
{/* add table of contents if it exists */}
|
{/* add table of contents if it exists */}
|
||||||
{!!fetchedPage.toc?.props.children.length && (
|
{!!fetchedPage.toc?.props.children.length && (
|
||||||
<PageTOC fetchedPage={fetchedPage} />
|
<Toc fetchedPage={fetchedPage} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* page content */}
|
{/* page content */}
|
Loading…
Add table
Add a link
Reference in a new issue