feat: add post toc

This commit is contained in:
DIYgod 2022-10-05 21:11:59 +01:00
parent 1258a97714
commit 576aed6e68
No known key found for this signature in database
GPG Key ID: D159328F47A80DCA
8 changed files with 65 additions and 21 deletions

View File

@ -58,6 +58,7 @@
"ioredis": "^5.2.3",
"js-yaml": "^4.1.0",
"mdast-util-to-string": "^3.1.0",
"mdast-util-toc": "^6.1.0",
"nanoid": "^4.0.0",
"next": "^12.3.1",
"nextjs-progressbar": "^0.0.14",
@ -89,7 +90,6 @@
"remark-parse": "^10.0.1",
"remark-rehype": "^10.1.0",
"remark-stringify": "^10.0.2",
"remark-toc": "^8.0.1",
"sharp": "^0.31.0",
"sortablejs": "^1.15.0",
"ua-parser-js": "^1.0.2",

View File

@ -76,6 +76,7 @@ specifiers:
js-yaml: ^4.1.0
lint-staged: ^13.0.3
mdast-util-to-string: ^3.1.0
mdast-util-toc: ^6.1.0
nanoid: ^4.0.0
next: ^12.3.1
nextjs-progressbar: ^0.0.14
@ -109,7 +110,6 @@ specifiers:
remark-parse: ^10.0.1
remark-rehype: ^10.1.0
remark-stringify: ^10.0.2
remark-toc: ^8.0.1
sharp: ^0.31.0
sortablejs: ^1.15.0
tailwindcss: ^3.1.8
@ -170,6 +170,7 @@ dependencies:
ioredis: 5.2.3
js-yaml: 4.1.0
mdast-util-to-string: 3.1.0
mdast-util-toc: 6.1.0
nanoid: 4.0.0
next: 12.3.1_biqbaboplfbrettd7655fr4n2y
nextjs-progressbar: 0.0.14_next@12.3.1+react@18.2.0
@ -201,7 +202,6 @@ dependencies:
remark-parse: 10.0.1
remark-rehype: 10.1.0
remark-stringify: 10.0.2
remark-toc: 8.0.1
sharp: 0.31.0
sortablejs: 1.15.0
ua-parser-js: 1.0.2
@ -9396,14 +9396,6 @@ packages:
unified: 10.1.2
dev: false
/remark-toc/8.0.1:
resolution: {integrity: sha512-7he2VOm/cy13zilnOTZcyAoyoolV26ULlon6XyCFU+vG54Z/LWJnwphj/xKIDLOt66QmJUgTyUvLVHi2aAElyg==}
dependencies:
'@types/mdast': 3.0.10
mdast-util-toc: 6.1.0
unified: 10.1.2
dev: false
/remove-accents/0.4.2:
resolution: {integrity: sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA==}
dev: false

View File

@ -5,7 +5,8 @@ import { renderPageContent } from "~/markdown"
export const PageContent: React.FC<{
content?: string
className?: string
}> = ({ className, content }) => {
toc?: boolean
}> = ({ className, content, toc }) => {
useCodeCopy()
// TODO
@ -21,7 +22,7 @@ export const PageContent: React.FC<{
return (
<div className={clsx("xlog-post-content", `prose`, className)}>
{content && renderPageContent(content).element}
{content && renderPageContent(content, false, toc).element}
</div>
)
}

View File

@ -0,0 +1,33 @@
import { useRef, useEffect, useState } from "react"
export const PostToc: React.FC<{
children: React.ReactNode
}> = ({ children }) => {
const containerRef = useRef<HTMLDivElement | null>(null)
const [maxWidth, setMaxWidth] = useState(0)
useEffect(() => {
if (containerRef?.current) {
setMaxWidth(
(window.innerWidth -
(containerRef.current?.parentElement?.clientWidth || 0)) /
2 -
40,
)
}
}, [containerRef])
return (
<div
className="xlog-post-toc absolute left-full pl-10 h-full top-0"
style={{
maxWidth: maxWidth > 40 ? maxWidth : 0,
}}
ref={containerRef}
>
<div className="sticky top-14 text-sm leading-loose whitespace-nowrap truncate text-ellipsis">
{children}
</div>
</div>
)
}

View File

@ -21,6 +21,7 @@ export const SitePage: React.FC<{
<PageContent
className="mt-10"
content={page?.body?.content}
toc={true}
></PageContent>
<PostFooter page={page} />
</>

View File

@ -1,5 +1,5 @@
.prose {
@apply text-zinc-600 leading-loose;
@apply text-zinc-600 leading-loose relative;
}
.prose > p {
@ -66,7 +66,7 @@
.prose ol {
@apply list-decimal;
@apply pl-5;
@apply pl-6;
}
.prose > ul,
@ -151,3 +151,7 @@
.prose .code-wrapper:hover .copy-button {
@apply inline-flex;
}
.xlog-post-toc a {
@apply truncate inline-block max-w-full align-bottom text-zinc-700 hover:text-accent-dark;
}

View File

@ -24,7 +24,8 @@ import { remarkYoutube } from "./remark-youtube"
import sanitizeScheme from "./sanitize-schema"
import rehypeSlug from "rehype-slug"
import rehypeAutolinkHeadings from "rehype-autolink-headings"
import remarkToc from "remark-toc"
import { toc } from "mdast-util-toc"
import { PostToc } from "~/components/site/PostToc"
export type MarkdownEnv = {
excerpt: string
@ -48,6 +49,7 @@ const rehypePrism = rehypePrismGenerator(refractor)
export const renderPageContent = (
content: string,
html?: boolean,
enableToc?: boolean,
): Rendered => {
const env: MarkdownEnv = {
excerpt: "",
@ -70,9 +72,18 @@ export const renderPageContent = (
console.log(e)
}
})
.use(remarkToc, {
tight: true,
ordered: true,
.use(() => (tree) => {
if (enableToc) {
const result = toc(tree, { tight: true, ordered: true })
if (result.map) {
tree.children = [
...tree.children,
{ type: "html", value: "<toc>" },
result.map,
{ type: "html", value: "</toc>" },
]
}
}
})
.use(remarkGfm, {})
.use(remarkExcerpt, { env })
@ -111,8 +122,9 @@ export const renderPageContent = (
.use(html ? () => (tree: any) => {} : rehypeReact, {
createElement: createElement,
components: {
img: Image as any,
},
img: Image,
toc: PostToc,
} as any,
})
.processSync(content)

View File

@ -9,6 +9,7 @@ const scheme = {
"iframe",
"style",
"youtube",
"toc",
],
attributes: {
...defaultSchema.attributes,