parent
ffd0a194de
commit
e838ac59f7
6 changed files with 24 additions and 51 deletions
|
@ -7,6 +7,7 @@ import markdownItSub from "markdown-it-sub" // markdown subscript
|
||||||
import markdownItSup from "markdown-it-sup" // markdown superscript
|
import markdownItSup from "markdown-it-sup" // markdown superscript
|
||||||
import highlightLines from "markdown-it-highlight-lines" // highlighting specific lines in code blocks
|
import highlightLines from "markdown-it-highlight-lines" // highlighting specific lines in code blocks
|
||||||
|
|
||||||
|
import toc from "markdown-toc" // table of contents generation
|
||||||
import hljs from "highlight.js" // code block syntax highlighting
|
import hljs from "highlight.js" // code block syntax highlighting
|
||||||
import katex from "katex" // rendering mathematical expression
|
import katex from "katex" // rendering mathematical expression
|
||||||
import "katex/contrib/mhchem" // chemical formula
|
import "katex/contrib/mhchem" // chemical formula
|
||||||
|
@ -47,3 +48,7 @@ export default function parseMarkdown(markdownRaw: string): string {
|
||||||
md.render(markdownRaw.slice(nthIndex(markdownRaw, "---", 2) + 3)) || ""
|
md.render(markdownRaw.slice(nthIndex(markdownRaw, "---", 2) + 3)) || ""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function generateToc(markdownRaw: string): string {
|
||||||
|
return md.render(toc(markdownRaw).content)
|
||||||
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import fs from "fs"
|
import fs from "fs"
|
||||||
import readTimeEstimate from "read-time-estimate" // post read time estimation
|
import readTimeEstimate from "read-time-estimate" // post read time estimation
|
||||||
import matter from "gray-matter" // parse markdown metadata
|
import matter from "gray-matter" // parse markdown metadata
|
||||||
import toc from "markdown-toc" // table of contents generation
|
|
||||||
import { JSDOM } from "jsdom" // HTML DOM parsing
|
import { JSDOM } from "jsdom" // HTML DOM parsing
|
||||||
|
|
||||||
import { nthIndex, path2FileOrFolderName, path2URL, writeToJSON } from "./util"
|
import { nthIndex, path2FileOrFolderName, path2URL, writeToJSON } from "./util"
|
||||||
import parseMarkdown from "./parseMarkdown"
|
import parseMarkdown, { generateToc } from "./parseMarkdown"
|
||||||
|
|
||||||
import { contentDirectoryPath } from "./config"
|
import { contentDirectoryPath } from "./config"
|
||||||
import { addDocument } from "./searchIndex"
|
import { addDocument } from "./searchIndex"
|
||||||
|
@ -186,7 +185,7 @@ function parsePost(data: DataToPass): void {
|
||||||
`${contentDirectoryPath}${urlPath}.json`,
|
`${contentDirectoryPath}${urlPath}.json`,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
content: markdownData.content,
|
content: markdownData.content,
|
||||||
toc: toc(markdownRaw).json,
|
toc: generateToc(markdownRaw),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -294,7 +293,7 @@ function parseSeries(data: DataToPass): void {
|
||||||
`${contentDirectoryPath}${urlPath}.json`,
|
`${contentDirectoryPath}${urlPath}.json`,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
content: markdownData.content,
|
content: markdownData.content,
|
||||||
toc: toc(markdownRaw).json,
|
toc: generateToc(markdownRaw),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,8 @@ import styled from "styled-components"
|
||||||
|
|
||||||
import theming from "../../styles/theming"
|
import theming from "../../styles/theming"
|
||||||
|
|
||||||
import { FetchedPage } from "../../../types/typing"
|
|
||||||
|
|
||||||
const StyledTocToggleButton = styled.button`
|
const StyledTocToggleButton = styled.button`
|
||||||
|
cursor: pointer;
|
||||||
border: none;
|
border: none;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
background-color: rgba(0, 0, 0, 0);
|
background-color: rgba(0, 0, 0, 0);
|
||||||
|
@ -29,7 +28,7 @@ const StyledCollapseContainer = styled.div`
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const Toc = (props: { fetchedPage: FetchedPage }) => {
|
const Toc = (props: { data?: string }) => {
|
||||||
const [isTocOpened, setIsTocOpened] = useState(
|
const [isTocOpened, setIsTocOpened] = useState(
|
||||||
storage.getItem("isTocOpened") == "true"
|
storage.getItem("isTocOpened") == "true"
|
||||||
)
|
)
|
||||||
|
@ -38,6 +37,8 @@ const Toc = (props: { fetchedPage: FetchedPage }) => {
|
||||||
storage.setItem("isTocOpened", isTocOpened.toString())
|
storage.setItem("isTocOpened", isTocOpened.toString())
|
||||||
}, [isTocOpened])
|
}, [isTocOpened])
|
||||||
|
|
||||||
|
if (!props.data) return <></>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledTocToggleButton
|
<StyledTocToggleButton
|
||||||
|
@ -54,7 +55,7 @@ const Toc = (props: { fetchedPage: FetchedPage }) => {
|
||||||
</StyledTocToggleButton>
|
</StyledTocToggleButton>
|
||||||
<StyledCollapseContainer>
|
<StyledCollapseContainer>
|
||||||
<Collapse isOpened={isTocOpened}>
|
<Collapse isOpened={isTocOpened}>
|
||||||
<div>{props.fetchedPage.toc}</div>
|
<div dangerouslySetInnerHTML={{ __html: props.data }} />
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</StyledCollapseContainer>
|
</StyledCollapseContainer>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
|
@ -2,9 +2,8 @@ import { useState } from "react"
|
||||||
import { Helmet } from "react-helmet-async"
|
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 { HashLink } from "react-router-hash-link"
|
|
||||||
|
|
||||||
import { TocElement, FetchedPage, Map } from "../../../types/typing"
|
import { FetchedPage, Map } from "../../../types/typing"
|
||||||
|
|
||||||
import MainContent from "../../components/MainContent"
|
import MainContent from "../../components/MainContent"
|
||||||
import Loading from "../../components/Loading"
|
import Loading from "../../components/Loading"
|
||||||
|
@ -29,21 +28,6 @@ const StyledTitle = styled.h1`
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
`
|
`
|
||||||
|
|
||||||
function parseToc(tocData: TocElement[]) {
|
|
||||||
return (
|
|
||||||
<ol>
|
|
||||||
{tocData.map((elem) => (
|
|
||||||
// use elem.lvl
|
|
||||||
<li key={elem.slug}>
|
|
||||||
<HashLink smooth to={location.pathname + "#" + elem.slug}>
|
|
||||||
{elem.content}
|
|
||||||
</HashLink>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ol>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SeriesData {
|
interface SeriesData {
|
||||||
seriesHome: string
|
seriesHome: string
|
||||||
prev?: string
|
prev?: string
|
||||||
|
@ -118,23 +102,14 @@ const Page = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchContent(_isUnsearchable, url).then((fetched_content) => {
|
fetchContent(_isUnsearchable, url).then((fetched_content) => {
|
||||||
fetchedPage.content = fetched_content.content
|
fetchedPage.content = fetched_content.content || "No content"
|
||||||
? fetched_content.content
|
|
||||||
: "No content"
|
|
||||||
fetchedPage.toc = fetched_content.toc
|
fetchedPage.toc = fetched_content.toc
|
||||||
? parseToc(fetched_content.toc)
|
|
||||||
: undefined
|
|
||||||
fetchedPage.title = _isUnsearchable
|
fetchedPage.title = _isUnsearchable
|
||||||
? map.unsearchable[url].title
|
? map.unsearchable[url].title
|
||||||
: fetchedPage?.title
|
: fetchedPage?.title || "No title"
|
||||||
? fetchedPage.title
|
|
||||||
: "No title"
|
|
||||||
|
|
||||||
if (!_isUnsearchable) {
|
if (!_isUnsearchable)
|
||||||
fetchedPage.date = fetchedPage?.date
|
fetchedPage.date = fetchedPage?.date || "Unknown date"
|
||||||
? fetchedPage.date
|
|
||||||
: "Unknown date"
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsSeries(_isSeries)
|
setIsSeries(_isSeries)
|
||||||
setFetchPage(fetchedPage)
|
setFetchPage(fetchedPage)
|
||||||
|
@ -193,9 +168,7 @@ const Page = () => {
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
{/* add table of contents if it exists */}
|
{/* add table of contents if it exists */}
|
||||||
{!!fetchedPage.toc?.props.children.length && (
|
<Toc data={fetchedPage.toc} />
|
||||||
<Toc fetchedPage={fetchedPage} />
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* page content */}
|
{/* page content */}
|
||||||
<div
|
<div
|
||||||
|
|
6
source/types/markdown-toc.d.ts
vendored
6
source/types/markdown-toc.d.ts
vendored
|
@ -1,4 +1,6 @@
|
||||||
declare module "markdown-toc" {
|
declare module "markdown-toc" {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
export default function toc(str: string): {
|
||||||
export default function toc(str: string): { json: JSON }
|
json: JSON
|
||||||
|
content: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,6 @@ export enum ParseMode {
|
||||||
UNSEARCHABLE,
|
UNSEARCHABLE,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TocElement {
|
|
||||||
slug: string
|
|
||||||
content: string
|
|
||||||
i: number
|
|
||||||
lvl: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Base {}
|
export interface Base {}
|
||||||
|
|
||||||
export interface PostData {
|
export interface PostData {
|
||||||
|
@ -37,7 +30,7 @@ export interface FetchedPage {
|
||||||
readTime: string
|
readTime: string
|
||||||
wordCount: number
|
wordCount: number
|
||||||
tags: string[]
|
tags: string[]
|
||||||
toc?: JSX.Element
|
toc?: string
|
||||||
content: string
|
content: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue