toc fixes and improvement

- close #7
- close #8
This commit is contained in:
Kim, Jimin 2021-12-19 20:09:14 +09:00
parent ffd0a194de
commit e838ac59f7
6 changed files with 24 additions and 51 deletions

View file

@ -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)
}

View file

@ -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),
}) })
) )
} }

View file

@ -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 />

View file

@ -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

View file

@ -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
}
} }

View file

@ -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
} }